了解底层才能理解程序的运作方式,了解汇编是深入了解Go的必经之路。

平台: mac intel

Go: 1.17

文中所用代码见附录

基础

段(section)

程序编译以后会分为不同的段,一般来说会分为

  1. .text 代码段 存放程序代码,通常是只读的
  2. .data 数据段 存放初始化了的全局变量和初始化了的静态变量
  3. .bss 全局变量段 存放未初始化的全局变量和未初始化的静态变量

名字都是历史定的,也没啥特殊硬记就完事。主要就是把数据按照不同的分类放在一起。也就是说可以自定义段信息来区分,能找到对应的数据就行。

查看段信息

查看段信息有几种方式

readelf

readelf -S 这个只支持elf格式的

1
2
GOOS=linux go build -gcflags="-B -N -l" main.go // 编译linux平台 // -B不开启越界检测 -N关闭优化 -l关闭内联
readelf -S main

可以得到以下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
There are 23 section headers, starting at offset 0x1c8:

Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .text PROGBITS 0000000000401000 00001000
000000000007ec6d 0000000000000000 AX 0 0 32
[ 2] .rodata PROGBITS 0000000000480000 00080000
0000000000035209 0000000000000000 A 0 0 32
[ 3] .shstrtab STRTAB 0000000000000000 000b5220
000000000000017a 0000000000000000 0 0 1
[ 4] .typelink PROGBITS 00000000004b53a0 000b53a0
00000000000004d8 0000000000000000 A 0 0 32
[ 5] .itablink PROGBITS 00000000004b5880 000b5880
0000000000000058 0000000000000000 A 0 0 32
[ 6] .gosymtab PROGBITS 00000000004b58d8 000b58d8
0000000000000000 0000000000000000 A 0 0 1
[ 7] .gopclntab PROGBITS 00000000004b58e0 000b58e0
000000000005a1f0 0000000000000000 A 0 0 32
[ 8] .go.buildinfo PROGBITS 0000000000510000 00110000
0000000000000020 0000000000000000 WA 0 0 16
[ 9] .noptrdata PROGBITS 0000000000510020 00110020
00000000000105e0 0000000000000000 WA 0 0 32
[10] .data PROGBITS 0000000000520600 00120600
0000000000007810 0000000000000000 WA 0 0 32
[11] .bss NOBITS 0000000000527e20 00127e20
000000000002ef28 0000000000000000 WA 0 0 32
[12] .noptrbss NOBITS 0000000000556d60 00156d60
0000000000005360 0000000000000000 WA 0 0 32
[13] .zdebug_abbrev PROGBITS 000000000055d000 00128000
0000000000000119 0000000000000000 0 0 1
[14] .zdebug_line PROGBITS 000000000055d119 00128119
000000000001b3c6 0000000000000000 0 0 1
[15] .zdebug_frame PROGBITS 00000000005784df 001434df
00000000000054a7 0000000000000000 0 0 1
[16] .debug_gdb_s[...] PROGBITS 000000000057d986 00148986
000000000000003e 0000000000000000 0 0 1
[17] .zdebug_info PROGBITS 000000000057d9c4 001489c4
000000000003146c 0000000000000000 0 0 1
[18] .zdebug_loc PROGBITS 00000000005aee30 00179e30
0000000000019635 0000000000000000 0 0 1
[19] .zdebug_ranges PROGBITS 00000000005c8465 00193465
0000000000008e9e 0000000000000000 0 0 1
[20] .note.go.buildid NOTE 0000000000400f9c 00000f9c
0000000000000064 0000000000000000 A 0 0 4
[21] .symtab SYMTAB 0000000000000000 0019c308
000000000000c420 0000000000000018 22 120 8
[22] .strtab STRTAB 0000000000000000 001a8728
000000000000b07c 0000000000000000 0 0 1

objdump

objdump -h 支持各种目标文件 这个mac需要brew install binutils安装一下

1
2
go build -gcflags="-B -N -l" main.go 
objdump -h main // -h 查看段头信息

可以得到以下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
main:     file format mach-o-x86-64

Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0008a9ed 0000000001001000 0000000001001000 00001000 2**5
CONTENTS, ALLOC, LOAD, CODE
1 __TEXT.__symbol_stub1 00000102 000000000108ba00 000000000108ba00 0008ba00 2**5
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 __TEXT.__rodata 000383f6 000000000108bb20 000000000108bb20 0008bb20 2**5
CONTENTS, ALLOC, LOAD, READONLY, CODE
3 __TEXT.__typelink 00000538 00000000010c3f20 00000000010c3f20 000c3f20 2**5
CONTENTS, ALLOC, LOAD, READONLY, CODE
4 __TEXT.__itablink 00000070 00000000010c4460 00000000010c4460 000c4460 2**5
CONTENTS, ALLOC, LOAD, READONLY, CODE
5 __TEXT.__gosymtab 00000000 00000000010c44d0 00000000010c44d0 000c44d0 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
6 __TEXT.__gopclntab 00061090 00000000010c44e0 00000000010c44e0 000c44e0 2**5
CONTENTS, ALLOC, LOAD, READONLY, CODE
7 __DATA.__go_buildinfo 00000020 0000000001126000 0000000001126000 00126000 2**4
CONTENTS, ALLOC, LOAD, DATA
8 __DATA.__nl_symbol_ptr 00000158 0000000001126020 0000000001126020 00126020 2**2
CONTENTS, ALLOC, LOAD, DATA
9 __DATA.__noptrdata 00010640 0000000001126180 0000000001126180 00126180 2**5
CONTENTS, ALLOC, LOAD, DATA
10 .data 00007470 00000000011367c0 00000000011367c0 001367c0 2**5
CONTENTS, ALLOC, LOAD, DATA
11 .bss 0002f048 000000000113dc40 000000000113dc40 00000000 2**5
ALLOC
12 __DATA.__noptrbss 000051c0 000000000116cca0 000000000116cca0 00000000 2**5
ALLOC
13 __DWARF.__zdebug_abbrev 00000117 0000000001172000 0000000001172000 0013e000 2**0
CONTENTS, DEBUGGING
14 __DWARF.__zdebug_line 0001d1ec 0000000001172117 0000000001172117 0013e117 2**0
CONTENTS, DEBUGGING
15 __DWARF.__zdebug_frame 00005acf 000000000118f303 000000000118f303 0015b303 2**0
CONTENTS, DEBUGGING
16 .debug_gdb_scripts 0000003e 0000000001194dd2 0000000001194dd2 00160dd2 2**0
CONTENTS, DEBUGGING
17 __DWARF.__zdebug_info 0003378d 0000000001194e10 0000000001194e10 00160e10 2**0
CONTENTS, DEBUGGING
18 __DWARF.__zdebug_loc 0001a2d5 00000000011c859d 00000000011c859d 0019459d 2**0
CONTENTS, DEBUGGING
19 __DWARF.__zdebug_ranges 000082a2 00000000011e2872 00000000011e2872 001ae872 2**0
CONTENTS, DEBUGGING
20 LC_THREAD.x86_THREAD_STATE64.0 000000a8 0000000000000000 0000000000000000 000007f0 2**0
CONTENTS

反汇编

go查看汇编有几种方式:

  1. go tool compile -S xxx.go
  2. go build -gcflags=”-S” xxx.go -gcflags其实就是把参数传给compile
  3. 先go build 编译,然后 go tool objdump -S xxx
  4. objdump -d

1/2 都是直接编译为汇编,生成的是过程中的机器码汇编。

3/4属于反汇编,生成是最终机器码汇编。

注意不管是生成的还是反汇编的,SP都是硬件SP,与手写汇编不一致。

这里我们以查看使用的string具体怎么存储,怎么读取的为例。

过程中的汇编

1
go tool compile -B -N -l -S main.go 

裁掉不关注信息可以得到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
"".main STEXT size=397 args=0x0 locals=0xc0 funcid=0x0
0x0000 00000 (main.go:21) TEXT "".main(SB), ABIInternal, $192-0
0x0000 00000 (main.go:21) LEAQ -64(SP), R12
0x0005 00005 (main.go:21) CMPQ R12, 16(R14)
0x0009 00009 (main.go:21) PCDATA $0, $-2
0x0009 00009 (main.go:21) JLS 387
0x000f 00015 (main.go:21) PCDATA $0, $-1
0x000f 00015 (main.go:21) SUBQ $192, SP
0x0016 00022 (main.go:21) MOVQ BP, 184(SP)
0x001e 00030 (main.go:21) LEAQ 184(SP), BP
0x0026 00038 (main.go:21) FUNCDATA $0, gclocals·69c1753bd5f81501d95132d08af04464(SB)
0x0026 00038 (main.go:21) FUNCDATA $1, gclocals·3d3dda67601e66e262180dc10a49f372(SB)
0x0026 00038 (main.go:21) FUNCDATA $2, "".main.stkobj(SB)
0x0026 00038 (main.go:22) LEAQ "".svz(SB), DX
0x002d 00045 (main.go:22) MOVQ DX, ""..autotmp_1+80(SP)
0x0032 00050 (main.go:22) MOVUPS X15, ""..autotmp_2+88(SP)
0x0038 00056 (main.go:22) LEAQ ""..autotmp_2+88(SP), AX
0x003d 00061 (main.go:22) MOVQ AX, ""..autotmp_5+72(SP)
0x0042 00066 (main.go:22) TESTB AL, (AX)
0x0044 00068 (main.go:22) MOVQ ""..autotmp_1+80(SP), DX
0x0049 00073 (main.go:22) LEAQ type.*string(SB), SI
0x0050 00080 (main.go:22) MOVQ SI, ""..autotmp_2+88(SP)
0x0055 00085 (main.go:22) MOVQ DX, ""..autotmp_2+96(SP)
0x005a 00090 (main.go:22) TESTB AL, (AX)
0x005c 00092 (main.go:22) MOVQ AX, ""..autotmp_4+128(SP)
0x0064 00100 (main.go:22) MOVQ $1, ""..autotmp_4+136(SP)
0x0070 00112 (main.go:22) MOVQ $1, ""..autotmp_4+144(SP)
0x007c 00124 (main.go:22) MOVL $1, BX
0x0081 00129 (main.go:22) MOVQ BX, CX
0x0084 00132 (main.go:22) PCDATA $1, $0
0x0084 00132 (main.go:22) CALL fmt.Println(SB)
0x0089 00137 (main.go:23) LEAQ "".svz(SB), DX
0x0090 00144 (main.go:23) TESTB AL, (DX)
0x0092 00146 (main.go:23) MOVQ "".svz(SB), DX
0x0099 00153 (main.go:23) MOVQ DX, "".trueV+40(SP)
0x009e 00158 (main.go:24) LEAQ ""..autotmp_3+152(SP), DX
0x00a6 00166 (main.go:24) MOVUPS X15, (DX)
0x00aa 00170 (main.go:24) LEAQ ""..autotmp_3+168(SP), DX
0x00b2 00178 (main.go:24) MOVUPS X15, (DX)
0x00b6 00182 (main.go:24) LEAQ ""..autotmp_3+152(SP), DX
0x00be 00190 (main.go:24) MOVQ DX, ""..autotmp_7+64(SP)
0x00c3 00195 (main.go:24) MOVQ "".trueV+40(SP), AX
0x00c8 00200 (main.go:24) PCDATA $1, $1
0x00c8 00200 (main.go:24) CALL runtime.convT64(SB)
0x00cd 00205 (main.go:24) MOVQ AX, ""..autotmp_8+56(SP)
0x00d2 00210 (main.go:24) MOVQ ""..autotmp_7+64(SP), DX
0x00d7 00215 (main.go:24) TESTB AL, (DX)
0x00d9 00217 (main.go:24) LEAQ type.uintptr(SB), SI
0x00e0 00224 (main.go:24) MOVQ SI, (DX)
0x00e3 00227 (main.go:24) LEAQ 8(DX), DI
0x00e7 00231 (main.go:24) PCDATA $0, $-2
0x00e7 00231 (main.go:24) CMPL runtime.writeBarrier(SB), $0
0x00ee 00238 (main.go:24) JEQ 242
0x00f0 00240 (main.go:24) JMP 248
0x00f2 00242 (main.go:24) MOVQ AX, 8(DX)
0x00f6 00246 (main.go:24) JMP 255
0x00f8 00248 (main.go:24) CALL runtime.gcWriteBarrier(SB)
0x00fd 00253 (main.go:24) JMP 255
0x00ff 00255 (main.go:24) PCDATA $0, $-1
0x00ff 00255 (main.go:24) MOVQ "".trueV+40(SP), AX
0x0104 00260 (main.go:24) CALL runtime.convT64(SB)
0x0109 00265 (main.go:24) MOVQ AX, ""..autotmp_9+48(SP)
0x010e 00270 (main.go:24) MOVQ ""..autotmp_7+64(SP), CX
0x0113 00275 (main.go:24) TESTB AL, (CX)
0x0115 00277 (main.go:24) LEAQ type.uintptr(SB), DX
0x011c 00284 (main.go:24) MOVQ DX, 16(CX)
0x0120 00288 (main.go:24) LEAQ 24(CX), DI
0x0124 00292 (main.go:24) PCDATA $0, $-2
0x0124 00292 (main.go:24) CMPL runtime.writeBarrier(SB), $0
0x012b 00299 (main.go:24) JEQ 303
0x012d 00301 (main.go:24) JMP 309
0x012f 00303 (main.go:24) MOVQ AX, 24(CX)
0x0133 00307 (main.go:24) JMP 316
0x0135 00309 (main.go:24) CALL runtime.gcWriteBarrier(SB)
0x013a 00314 (main.go:24) JMP 316
0x013c 00316 (main.go:24) PCDATA $0, $-1
0x013c 00316 (main.go:24) MOVQ ""..autotmp_7+64(SP), CX
0x0141 00321 (main.go:24) TESTB AL, (CX)
0x0143 00323 (main.go:24) MOVQ CX, ""..autotmp_6+104(SP)
0x0148 00328 (main.go:24) MOVQ $2, ""..autotmp_6+112(SP)
0x0151 00337 (main.go:24) MOVQ $2, ""..autotmp_6+120(SP)
0x015a 00346 (main.go:24) LEAQ go.string."0x%x | %v\n"(SB), AX
0x0161 00353 (main.go:24) MOVL $10, BX
0x0166 00358 (main.go:24) MOVL $2, DI
0x016b 00363 (main.go:24) MOVQ DI, SI
0x016e 00366 (main.go:24) PCDATA $1, $0
0x016e 00366 (main.go:24) CALL fmt.Printf(SB)
0x0173 00371 (main.go:25) MOVQ 184(SP), BP
0x017b 00379 (main.go:25) ADDQ $192, SP
0x0182 00386 (main.go:25) RET
0x0183 00387 (main.go:25) NOP
0x0183 00387 (main.go:21) PCDATA $1, $-1
0x0183 00387 (main.go:21) PCDATA $0, $-2
0x0183 00387 (main.go:21) CALL runtime.morestack_noctxt(SB)
0x0188 00392 (main.go:21) PCDATA $0, $-1
0x0188 00392 (main.go:21) JMP 0
0x0000 4c 8d 64 24 c0 4d 3b 66 10 0f 86 74 01 00 00 48 L.d$.M;f...t...H
0x0010 81 ec c0 00 00 00 48 89 ac 24 b8 00 00 00 48 8d ......H..$....H.
0x0020 ac 24 b8 00 00 00 48 8d 15 00 00 00 00 48 89 54 .$....H......H.T
0x0030 24 50 44 0f 11 7c 24 58 48 8d 44 24 58 48 89 44 $PD..|$XH.D$XH.D
0x0040 24 48 84 00 48 8b 54 24 50 48 8d 35 00 00 00 00 $H..H.T$PH.5....
0x0050 48 89 74 24 58 48 89 54 24 60 84 00 48 89 84 24 H.t$XH.T$`..H..$
0x0060 80 00 00 00 48 c7 84 24 88 00 00 00 01 00 00 00 ....H..$........
0x0070 48 c7 84 24 90 00 00 00 01 00 00 00 bb 01 00 00 H..$............
0x0080 00 48 89 d9 e8 00 00 00 00 48 8d 15 00 00 00 00 .H.......H......
0x0090 84 02 48 8b 15 00 00 00 00 48 89 54 24 28 48 8d ..H......H.T$(H.
0x00a0 94 24 98 00 00 00 44 0f 11 3a 48 8d 94 24 a8 00 .$....D..:H..$..
0x00b0 00 00 44 0f 11 3a 48 8d 94 24 98 00 00 00 48 89 ..D..:H..$....H.
0x00c0 54 24 40 48 8b 44 24 28 e8 00 00 00 00 48 89 44 T$@H.D$(.....H.D
0x00d0 24 38 48 8b 54 24 40 84 02 48 8d 35 00 00 00 00 $8H.T$@..H.5....
0x00e0 48 89 32 48 8d 7a 08 83 3d 00 00 00 00 00 74 02 H.2H.z..=.....t.
0x00f0 eb 06 48 89 42 08 eb 07 e8 00 00 00 00 eb 00 48 ..H.B..........H
0x0100 8b 44 24 28 e8 00 00 00 00 48 89 44 24 30 48 8b .D$(.....H.D$0H.
0x0110 4c 24 40 84 01 48 8d 15 00 00 00 00 48 89 51 10 L$@..H......H.Q.
0x0120 48 8d 79 18 83 3d 00 00 00 00 00 74 02 eb 06 48 H.y..=.....t...H
0x0130 89 41 18 eb 07 e8 00 00 00 00 eb 00 48 8b 4c 24 .A..........H.L$
0x0140 40 84 01 48 89 4c 24 68 48 c7 44 24 70 02 00 00 @..H.L$hH.D$p...
0x0150 00 48 c7 44 24 78 02 00 00 00 48 8d 05 00 00 00 .H.D$x....H.....
0x0160 00 bb 0a 00 00 00 bf 02 00 00 00 48 89 fe e8 00 ...........H....
0x0170 00 00 00 48 8b ac 24 b8 00 00 00 48 81 c4 c0 00 ...H..$....H....
0x0180 00 00 c3 e8 00 00 00 00 e9 73 fe ff ff .........s...
rel 3+0 t=24 type.*string+0
rel 3+0 t=24 type.uintptr+0
rel 3+0 t=24 type.uintptr+0
rel 41+4 t=15 "".svz+0
rel 76+4 t=15 type.*string+0
rel 133+4 t=7 fmt.Println+0
rel 140+4 t=15 "".svz+0
rel 149+4 t=15 "".svz+0
rel 201+4 t=7 runtime.convT64+0
rel 220+4 t=15 type.uintptr+0
rel 233+4 t=15 runtime.writeBarrier+-1
rel 249+4 t=7 runtime.gcWriteBarrier+0
rel 261+4 t=7 runtime.convT64+0
rel 280+4 t=15 type.uintptr+0
rel 294+4 t=15 runtime.writeBarrier+-1
rel 310+4 t=7 runtime.gcWriteBarrier+0
rel 349+4 t=15 go.string."0x%x | %v\n"+0
rel 367+4 t=7 fmt.Printf+0
rel 388+4 t=7 runtime.morestack_noctxt+0
go.string."svz-svz" SRODATA dupok size=7
0x0000 73 76 7a 2d 73 76 7a svz-svz
go.string."0x%x | %v\n" SRODATA dupok size=10
0x0000 30 78 25 78 20 7c 20 25 76 0a 0x%x | %v.
"".svz SDATA size=16
0x0000 00 00 00 00 00 00 00 00 07 00 00 00 00 00 00 00 ................
rel 0+8 t=1 go.string."svz-svz"+0
runtime.gcbits.02 SRODATA dupok size=1
0x0000 02 .
runtime.gcbits.0a SRODATA dupok size=1
0x0000 0a .
type..importpath.fmt. SRODATA dupok size=5
0x0000 00 03 66 6d 74 ..fmt
type..importpath.reflect. SRODATA dupok size=9
0x0000 00 07 72 65 66 6c 65 63 74 ..reflect
type..importpath.unsafe. SRODATA dupok size=8
0x0000 00 06 75 6e 73 61 66 65 ..unsafe
gclocals·69c1753bd5f81501d95132d08af04464 SRODATA dupok size=8
0x0000 02 00 00 00 00 00 00 00 ........
gclocals·3d3dda67601e66e262180dc10a49f372 SRODATA dupok size=14
0x0000 02 00 00 00 11 00 00 00 00 00 00 04 00 00 ..............
"".main.stkobj SRODATA static size=56
0x0000 02 00 00 00 00 00 00 00 a0 ff ff ff 10 00 00 00 ................
0x0010 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x0020 e0 ff ff ff 20 00 00 00 20 00 00 00 00 00 00 00 .... ... .......
0x0030 00 00 00 00 00 00 00 00 ........
rel 24+8 t=1 runtime.gcbits.02+0
rel 48+8 t=1 runtime.gcbits.0a+0

S(ymbol)开头的表示符号类型 具体可见SymbolKind

DATA 表示数据,RODATA 表示只读数据

TEXT 表示符号

dupok 表示数据只有一份

解析

挑重点看一下

  1. 符号定义

    "".main STEXT size=397 args=0x0 locals=0xc0 funcid=0x0

    “”.main 是符号名

    STEXT 表示符号是函数

    size为占用大小

    args参数大小

    locals局部变量大小

    funcid表示函数类型0为普通函数,具体可见funcid

下方跟了一段反编译代码

反编译代码后为原始二进制编码

再下方为引用的数据,简单看一个

rel 140+4 t=15 "".svz+0

分别为 rel 偏移+长度 t=重定位类型(具体定义见RelocType) 符号名+偏移量

140号位置也就是(0x8c)长度为4字节的空间为””.svz+0的数据引用

可以具体位置0x0080 00 48 89 d9 e8 00 00 00 00 48 8d 15 00 00 00 00 .H.......H......最后四子节全为0,因为是引用数据

  1. 字符串定义

    1
    2
    go.string."svz-svz" SRODATA dupok size=7
    0x0000 73 76 7a 2d 73 76 7a svz-svz

    go.string.”svz-svz” 符号名

    SRODATA 表示符号是只读数据

    dupok 表示只有一份

    size 为占用大小

  2. 变量定义

    1
    2
    3
      "".svz SDATA size=16
    0x0000 00 00 00 00 00 00 00 00 07 00 00 00 00 00 00 00 ................
    rel 0+8 t=1 go.string."svz-svz"+0

    “”.svz 符号名

    SDATA 表示符号是数据

    size 为占用大小 16是因为字符串底层为 data指针+长度

    先看后8字节 07 00 00 00 00 00 00 00 因为是小端,实际为00 00 00 00 00 00 00 07 也就是7

    再看下方的rel

    0号位置长度为8字节的空间 为go.string.”svz-svz”+0的数据引用

过程中的就只能看到这么多信息了。

最终的汇编

先看go tool的版本

1
go tool objdump -gnu -s main.main main // -gnu 同时输出gnu风格的汇编 -s 匹配指定符号名

裁出来main函数汇编如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
TEXT main.main(SB) /Users/svz/code/test/test/main.go
main.go:21 0x108b860 4c8d6424c0 LEAQ -0x40(SP), R12 // lea -0x40(%rsp),%r12
main.go:21 0x108b865 4d3b6610 CMPQ 0x10(R14), R12 // cmp 0x10(%r14),%r12
main.go:21 0x108b869 0f8674010000 JBE 0x108b9e3 // jbe 0x108b9e3
main.go:21 0x108b86f 4881ecc0000000 SUBQ $0xc0, SP // sub $0xc0,%rsp
main.go:21 0x108b876 4889ac24b8000000 MOVQ BP, 0xb8(SP) // mov %rbp,0xb8(%rsp)
main.go:21 0x108b87e 488dac24b8000000 LEAQ 0xb8(SP), BP // lea 0xb8(%rsp),%rbp
main.go:22 0x108b886 488d1503b70a00 LEAQ main.svz(SB), DX // lea 0xab703(%rip),%rdx
main.go:22 0x108b88d 4889542450 MOVQ DX, 0x50(SP) // mov %rdx,0x50(%rsp)
main.go:22 0x108b892 440f117c2458 MOVUPS X15, 0x58(SP) // movups %xmm15,0x58(%rsp)
main.go:22 0x108b898 488d442458 LEAQ 0x58(SP), AX // lea 0x58(%rsp),%rax
main.go:22 0x108b89d 4889442448 MOVQ AX, 0x48(SP) // mov %rax,0x48(%rsp)
main.go:22 0x108b8a2 8400 TESTB AL, 0(AX) // test %al,(%rax)
main.go:22 0x108b8a4 488b542450 MOVQ 0x50(SP), DX // mov 0x50(%rsp),%rdx
main.go:22 0x108b8a9 488d35105d0000 LEAQ runtime.types+23200(SB), SI // lea 0x5d10(%rip),%rsi
main.go:22 0x108b8b0 4889742458 MOVQ SI, 0x58(SP) // mov %rsi,0x58(%rsp)
main.go:22 0x108b8b5 4889542460 MOVQ DX, 0x60(SP) // mov %rdx,0x60(%rsp)
main.go:22 0x108b8ba 8400 TESTB AL, 0(AX) // test %al,(%rax)
main.go:22 0x108b8bc 4889842480000000 MOVQ AX, 0x80(SP) // mov %rax,0x80(%rsp)
main.go:22 0x108b8c4 48c784248800000001000000 MOVQ $0x1, 0x88(SP) // movq $0x1,0x88(%rsp)
main.go:22 0x108b8d0 48c784249000000001000000 MOVQ $0x1, 0x90(SP) // movq $0x1,0x90(%rsp)
main.go:22 0x108b8dc bb01000000 MOVL $0x1, BX // mov $0x1,%ebx
main.go:22 0x108b8e1 4889d9 MOVQ BX, CX // mov %rbx,%rcx
main.go:22 0x108b8e4 e8d795ffff CALL fmt.Println(SB) // callq 0x1084ec0
main.go:23 0x108b8e9 488d15a0b60a00 LEAQ main.svz(SB), DX // lea 0xab6a0(%rip),%rdx
main.go:23 0x108b8f0 8402 TESTB AL, 0(DX) // test %al,(%rdx)
main.go:23 0x108b8f2 488b1597b60a00 MOVQ main.svz(SB), DX // mov 0xab697(%rip),%rdx
main.go:23 0x108b8f9 4889542428 MOVQ DX, 0x28(SP) // mov %rdx,0x28(%rsp)
main.go:24 0x108b8fe 488d942498000000 LEAQ 0x98(SP), DX // lea 0x98(%rsp),%rdx
main.go:24 0x108b906 440f113a MOVUPS X15, 0(DX) // movups %xmm15,(%rdx)
main.go:24 0x108b90a 488d9424a8000000 LEAQ 0xa8(SP), DX // lea 0xa8(%rsp),%rdx
main.go:24 0x108b912 440f113a MOVUPS X15, 0(DX) // movups %xmm15,(%rdx)
main.go:24 0x108b916 488d942498000000 LEAQ 0x98(SP), DX // lea 0x98(%rsp),%rdx
main.go:24 0x108b91e 4889542440 MOVQ DX, 0x40(SP) // mov %rdx,0x40(%rsp)
main.go:24 0x108b923 488b442428 MOVQ 0x28(SP), AX // mov 0x28(%rsp),%rax
main.go:24 0x108b928 e893d8f7ff CALL runtime.convT64(SB) // callq 0x10091c0
main.go:24 0x108b92d 4889442438 MOVQ AX, 0x38(SP) // mov %rax,0x38(%rsp)
main.go:24 0x108b932 488b542440 MOVQ 0x40(SP), DX // mov 0x40(%rsp),%rdx
main.go:24 0x108b937 8402 TESTB AL, 0(DX) // test %al,(%rdx)
main.go:24 0x108b939 488d35007b0000 LEAQ runtime.types+31008(SB), SI // lea 0x7b00(%rip),%rsi
main.go:24 0x108b940 488932 MOVQ SI, 0(DX) // mov %rsi,(%rdx)
main.go:24 0x108b943 488d7a08 LEAQ 0x8(DX), DI // lea 0x8(%rdx),%rdi
main.go:24 0x108b947 833dd2150e0000 CMPL $0x0, runtime.writeBarrier(SB) // cmpl $0x0,0xe15d2(%rip)
main.go:24 0x108b94e 7402 JE 0x108b952 // je 0x108b952
main.go:24 0x108b950 eb06 JMP 0x108b958 // jmp 0x108b958
main.go:24 0x108b952 48894208 MOVQ AX, 0x8(DX) // mov %rax,0x8(%rdx)
main.go:24 0x108b956 eb07 JMP 0x108b95f // jmp 0x108b95f
main.go:24 0x108b958 e8c3f7fcff CALL runtime.gcWriteBarrier(SB) // callq 0x105b120
main.go:24 0x108b95d eb00 JMP 0x108b95f // jmp 0x108b95f
main.go:24 0x108b95f 488b442428 MOVQ 0x28(SP), AX // mov 0x28(%rsp),%rax
main.go:24 0x108b964 e857d8f7ff CALL runtime.convT64(SB) // callq 0x10091c0
main.go:24 0x108b969 4889442430 MOVQ AX, 0x30(SP) // mov %rax,0x30(%rsp)
main.go:24 0x108b96e 488b4c2440 MOVQ 0x40(SP), CX // mov 0x40(%rsp),%rcx
main.go:24 0x108b973 8401 TESTB AL, 0(CX) // test %al,(%rcx)
main.go:24 0x108b975 488d15c47a0000 LEAQ runtime.types+31008(SB), DX // lea 0x7ac4(%rip),%rdx
main.go:24 0x108b97c 48895110 MOVQ DX, 0x10(CX) // mov %rdx,0x10(%rcx)
main.go:24 0x108b980 488d7918 LEAQ 0x18(CX), DI // lea 0x18(%rcx),%rdi
main.go:24 0x108b984 833d95150e0000 CMPL $0x0, runtime.writeBarrier(SB) // cmpl $0x0,0xe1595(%rip)
main.go:24 0x108b98b 7402 JE 0x108b98f // je 0x108b98f
main.go:24 0x108b98d eb06 JMP 0x108b995 // jmp 0x108b995
main.go:24 0x108b98f 48894118 MOVQ AX, 0x18(CX) // mov %rax,0x18(%rcx)
main.go:24 0x108b993 eb07 JMP 0x108b99c // jmp 0x108b99c
main.go:24 0x108b995 e886f7fcff CALL runtime.gcWriteBarrier(SB) // callq 0x105b120
main.go:24 0x108b99a eb00 JMP 0x108b99c // jmp 0x108b99c
main.go:24 0x108b99c 488b4c2440 MOVQ 0x40(SP), CX // mov 0x40(%rsp),%rcx
main.go:24 0x108b9a1 8401 TESTB AL, 0(CX) // test %al,(%rcx)
main.go:24 0x108b9a3 48894c2468 MOVQ CX, 0x68(SP) // mov %rcx,0x68(%rsp)
main.go:24 0x108b9a8 48c744247002000000 MOVQ $0x2, 0x70(SP) // movq $0x2,0x70(%rsp)
main.go:24 0x108b9b1 48c744247802000000 MOVQ $0x2, 0x78(SP) // movq $0x2,0x78(%rsp)
main.go:24 0x108b9ba 488d053d840100 LEAQ go.string.*+3230(SB), AX // lea 0x1843d(%rip),%rax
main.go:24 0x108b9c1 bb0a000000 MOVL $0xa, BX // mov $0xa,%ebx
main.go:24 0x108b9c6 bf02000000 MOVL $0x2, DI // mov $0x2,%edi
main.go:24 0x108b9cb 4889fe MOVQ DI, SI // mov %rdi,%rsi
main.go:24 0x108b9ce e84d93ffff CALL fmt.Printf(SB) // callq 0x1084d20
main.go:25 0x108b9d3 488bac24b8000000 MOVQ 0xb8(SP), BP // mov 0xb8(%rsp),%rbp
main.go:25 0x108b9db 4881c4c0000000 ADDQ $0xc0, SP // add $0xc0,%rsp
main.go:25 0x108b9e2 c3 RET // retq
main.go:21 0x108b9e3 e858d7fcff CALL runtime.morestack_noctxt.abi0(SB) // callq 0x1059140
main.go:21 0x108b9e8 e973feffff JMP main.main(SB) // jmpq 0x108b860

这里生成的就带上了具体地址信息了

把使用字符串的挑出来看

main.go:22 0x108b886 488d1503b70a00 LEAQ main.svz(SB), DX // lea 0xab703(%rip),%rdx

可以看到把main.svz(SB)的地址放到了DX,1.17之后为寄存器传参

对应的gnu汇编则是将0xab703(%rip)地址放到了%rdx,0xab703(%rip)换算过来就是0x1136f90,对比运行结果就是变量svz的地址

对于go tool来说,也只能看到这一层了,想要再深一点就得上objdump了

下面来用objdump来看

1
objdump -d -j .text  main

截取main.main部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
000000000108b860 <_main.main>:
108b860: 4c 8d 64 24 c0 lea -0x40(%rsp),%r12
108b865: 4d 3b 66 10 cmp 0x10(%r14),%r12
108b869: 0f 86 74 01 00 00 jbe 108b9e3 <_main.main+0x183>
108b86f: 48 81 ec c0 00 00 00 sub $0xc0,%rsp
108b876: 48 89 ac 24 b8 00 00 mov %rbp,0xb8(%rsp)
108b87d: 00
108b87e: 48 8d ac 24 b8 00 00 lea 0xb8(%rsp),%rbp
108b885: 00
108b886: 48 8d 15 03 b7 0a 00 lea 0xab703(%rip),%rdx # 1136f90 <_main.svz>
108b88d: 48 89 54 24 50 mov %rdx,0x50(%rsp)
108b892: 44 0f 11 7c 24 58 movups %xmm15,0x58(%rsp)
108b898: 48 8d 44 24 58 lea 0x58(%rsp),%rax
108b89d: 48 89 44 24 48 mov %rax,0x48(%rsp)
108b8a2: 84 00 test %al,(%rax)
108b8a4: 48 8b 54 24 50 mov 0x50(%rsp),%rdx
108b8a9: 48 8d 35 10 5d 00 00 lea 0x5d10(%rip),%rsi # 10915c0 <_runtime.rodata+0x5aa0>
108b8b0: 48 89 74 24 58 mov %rsi,0x58(%rsp)
108b8b5: 48 89 54 24 60 mov %rdx,0x60(%rsp)
108b8ba: 84 00 test %al,(%rax)
108b8bc: 48 89 84 24 80 00 00 mov %rax,0x80(%rsp)
108b8c3: 00
108b8c4: 48 c7 84 24 88 00 00 movq $0x1,0x88(%rsp)
108b8cb: 00 01 00 00 00
108b8d0: 48 c7 84 24 90 00 00 movq $0x1,0x90(%rsp)
108b8d7: 00 01 00 00 00
108b8dc: bb 01 00 00 00 mov $0x1,%ebx
108b8e1: 48 89 d9 mov %rbx,%rcx
108b8e4: e8 d7 95 ff ff call 1084ec0 <_fmt.Println>
108b8e9: 48 8d 15 a0 b6 0a 00 lea 0xab6a0(%rip),%rdx # 1136f90 <_main.svz>
108b8f0: 84 02 test %al,(%rdx)
108b8f2: 48 8b 15 97 b6 0a 00 mov 0xab697(%rip),%rdx # 1136f90 <_main.svz>
108b8f9: 48 89 54 24 28 mov %rdx,0x28(%rsp)
108b8fe: 48 8d 94 24 98 00 00 lea 0x98(%rsp),%rdx
108b905: 00
108b906: 44 0f 11 3a movups %xmm15,(%rdx)
108b90a: 48 8d 94 24 a8 00 00 lea 0xa8(%rsp),%rdx
108b911: 00
108b912: 44 0f 11 3a movups %xmm15,(%rdx)
108b916: 48 8d 94 24 98 00 00 lea 0x98(%rsp),%rdx
108b91d: 00
108b91e: 48 89 54 24 40 mov %rdx,0x40(%rsp)
108b923: 48 8b 44 24 28 mov 0x28(%rsp),%rax
108b928: e8 93 d8 f7 ff call 10091c0 <_runtime.convT64>
108b92d: 48 89 44 24 38 mov %rax,0x38(%rsp)
108b932: 48 8b 54 24 40 mov 0x40(%rsp),%rdx
108b937: 84 02 test %al,(%rdx)
108b939: 48 8d 35 00 7b 00 00 lea 0x7b00(%rip),%rsi # 1093440 <_runtime.rodata+0x7920>
108b940: 48 89 32 mov %rsi,(%rdx)
108b943: 48 8d 7a 08 lea 0x8(%rdx),%rdi
108b947: 83 3d d2 15 0e 00 00 cmpl $0x0,0xe15d2(%rip) # 116cf20 <_runtime.writeBarrier>
108b94e: 74 02 je 108b952 <_main.main+0xf2>
108b950: eb 06 jmp 108b958 <_main.main+0xf8>
108b952: 48 89 42 08 mov %rax,0x8(%rdx)
108b956: eb 07 jmp 108b95f <_main.main+0xff>
108b958: e8 c3 f7 fc ff call 105b120 <_runtime.gcWriteBarrier>
108b95d: eb 00 jmp 108b95f <_main.main+0xff>
108b95f: 48 8b 44 24 28 mov 0x28(%rsp),%rax
108b964: e8 57 d8 f7 ff call 10091c0 <_runtime.convT64>
108b969: 48 89 44 24 30 mov %rax,0x30(%rsp)
108b96e: 48 8b 4c 24 40 mov 0x40(%rsp),%rcx
108b973: 84 01 test %al,(%rcx)
108b975: 48 8d 15 c4 7a 00 00 lea 0x7ac4(%rip),%rdx # 1093440 <_runtime.rodata+0x7920>
108b97c: 48 89 51 10 mov %rdx,0x10(%rcx)
108b980: 48 8d 79 18 lea 0x18(%rcx),%rdi
108b984: 83 3d 95 15 0e 00 00 cmpl $0x0,0xe1595(%rip) # 116cf20 <_runtime.writeBarrier>
108b98b: 74 02 je 108b98f <_main.main+0x12f>
108b98d: eb 06 jmp 108b995 <_main.main+0x135>
108b98f: 48 89 41 18 mov %rax,0x18(%rcx)
108b993: eb 07 jmp 108b99c <_main.main+0x13c>
108b995: e8 86 f7 fc ff call 105b120 <_runtime.gcWriteBarrier>
108b99a: eb 00 jmp 108b99c <_main.main+0x13c>
108b99c: 48 8b 4c 24 40 mov 0x40(%rsp),%rcx
108b9a1: 84 01 test %al,(%rcx)
108b9a3: 48 89 4c 24 68 mov %rcx,0x68(%rsp)
108b9a8: 48 c7 44 24 70 02 00 movq $0x2,0x70(%rsp)
108b9af: 00 00
108b9b1: 48 c7 44 24 78 02 00 movq $0x2,0x78(%rsp)
108b9b8: 00 00
108b9ba: 48 8d 05 3d 84 01 00 lea 0x1843d(%rip),%rax # 10a3dfe <_go.string.*+0xc9e>
108b9c1: bb 0a 00 00 00 mov $0xa,%ebx
108b9c6: bf 02 00 00 00 mov $0x2,%edi
108b9cb: 48 89 fe mov %rdi,%rsi
108b9ce: e8 4d 93 ff ff call 1084d20 <_fmt.Printf>
108b9d3: 48 8b ac 24 b8 00 00 mov 0xb8(%rsp),%rbp
108b9da: 00
108b9db: 48 81 c4 c0 00 00 00 add $0xc0,%rsp
108b9e2: c3 ret
108b9e3: e8 58 d7 fc ff call 1059140 <_runtime.morestack_noctxt.abi0>
108b9e8: e9 73 fe ff ff jmp 108b860 <_main.main>

还是捞出使用string的

1
108b886:   48 8d 15 03 b7 0a 00    lea    0xab703(%rip),%rdx        # 1136f90 <_main.svz>

可以看到和go tool的地址一致,也就是0x1136f90,这里直接帮忙计算出来了,免得自己算

通过上方头信息可以得知1136f90在data段

再来看data段信息

1
objdump -s -j .data  main

截取1136f90的部分

1
1136f90 ae380a01 00000000 07000000 00000000  .8..............

可以看到16字节内容,其实就是变量svz的内容

拆成两段,

ae380a01 00000000 小端模式转换出来就是 010a38ae 对比程序输出就是实际字符位置

07000000 00000000 小端模式转换出来就是7,也就是长度

通过上方头信息得知010a38ae__TEXT.__rodata

再来看__TEXT.__rodata段信息

1
objdump -s -j __TEXT.__rodata main

裁出来010a38ae部分

1
2
10a38a0 72756e6e 696e6773 69676e61 6c207376  runningsignal sv
10a38b0 7a2d7376 7a737973 63616c6c 75696e74 z-svzsyscalluint

可以看到010a38ae部分为svz-svz即我们给的值

附录

  1. 示例代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    /**
    * @file main.go
    * @author 903943711@qq.com
    * ___ _ _ ____
    * / __)( \/ )(_ )
    * \__ \ \ / / /_
    * (___/ \/ (____)
    * @date 2021/9/8
    * @desc
    */
    package main

    import (
    "fmt"
    "reflect"
    "unsafe"
    )

    var svz = "svz-svz"

    func main() {
    fmt.Println(&svz)
    trueV := (*reflect.StringHeader)(unsafe.Pointer(&svz)).Data
    fmt.Printf("0x%x | %v\n", trueV, trueV)
    }