Go version: 1.16
Assembly instruction
AMD64 rax rbx rcx rdx rdi rsi rbp rsp r8 r9 r10 r11 r12 r13 r14 rip
Plan9 AX BX CX DX DI SI BP SP R8 R9 R10 R11 R12 R13 R14 PC
Copy the code
rip
Register: Stores theCPU
The memory address of the next instruction to be executed. thisrip
isCPU
Automatic control, we don’t have to modify.rsp
Stack top register andrbp
Stack base register:rsp
Store the top address of stack frame,rbp
Store the start address of the stack frame.- Other registers, no special provisions, we can use them for our own use
The Go program predefined four pseudo registers
FP
: Frame pointer: arguments and locals.PC
: Program counter: jumps and branches.SB
: Static base pointer: global symbols.SP
: Stack pointer: the highest address within the local stack frame.
X86 assembly
Method: Compile the code into an executable program and then disassemble it into platform-specific assembly code through GDB
package main
func sum(a, b int) int {
c := a + b
return c
}
func main(a) {
sum(1.2)}Copy the code
compile
go build -gcflags "-N -l" main.go
Use GDB disassembly
gdb main
~/workspace/study/$GDB main ✔ 1h 21m 15S 22:16:31
GNU gdb (GDB) 11.1
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "X86_64 - apple - darwin20.4.0".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word". Reading symbols from main... (No debugging symbols found in main) Loading Go Runtime support. (gdb) disas'main.main' // Disassemble main function
Dump of assembler code for function main.main:
0x000000000105e2a0 <+0>: mov %gs:0x30,%rcx
0x000000000105e2a9 <+9>: cmp 0x10(%rcx),%rsp
0x000000000105e2ad <+13>: jbe 0x105e2e0 <main.main+64>
0x000000000105e2af <+15>: sub $0x20,%rsp
0x000000000105e2b3 <+19>: mov %rbp,0x18(%rsp)
0x000000000105e2b8 <+24>: lea 0x18(%rsp),%rbp
0x000000000105e2bd <+29>: movq $0x1,(%rsp)
0x000000000105e2c5 <+37>: movq $0x2.0x8(%rsp)
0x000000000105e2ce <+46>: call 0x105e260 <main.sum>
0x000000000105e2d3 <+51>: mov 0x18(%rsp),%rbp
0x000000000105e2d8 <+56>: add $0x20,%rsp
0x000000000105e2dc <+60>: ret
0x000000000105e2dd <+61>: nopl (%rax)
0x000000000105e2e0 <+64>: call 0x1059560 <runtime.morestack_noctxt>
0x000000000105e2e5 <+69>: jmp 0x105e2a0 <main.main>
End of assembler dump.
(gdb) b *0x000000000105e2a0 // Set a breakpoint at the first line of the main assembly code
Breakpoint 1 at 0x105e2a0
(gdb) r // Run and stop at the breakpoint
Starting program: /Users/zixuan.xu/workspace/study/learn-go-plan9/goroutine/main
[New Thread 0x2b03 of process 27105]
[New Thread 0x5403 of process 27105]
warning: unhandled dyld version (17)
[New Thread 0x2c07 of process 27105]
[New Thread 0x2e03 of process 27105]
[New Thread 0x3003 of process 27105]
[New Thread 0x5303 of process 27105]
Thread 2 hit Breakpoint 1.0x000000000105e2a0 in main.main ()
(gdb) disas // Lists the assembly code
Dump of assembler code for function main.main:
=> 0x000000000105e2a0 <+0>: mov %gs:0x30,%rcx // => Indicates the location of the current block
0x000000000105e2a9 <+9>: cmp 0x10(%rcx),%rsp
0x000000000105e2ad <+13>: jbe 0x105e2e0 <main.main+64>
0x000000000105e2af <+15>: sub $0x20,%rsp
0x000000000105e2b3 <+19>: mov %rbp,0x18(%rsp)
0x000000000105e2b8 <+24>: lea 0x18(%rsp),%rbp
0x000000000105e2bd <+29>: movq $0x1,(%rsp)
0x000000000105e2c5 <+37>: movq $0x2.0x8(%rsp)
0x000000000105e2ce <+46>: call 0x105e260 <main.sum>
0x000000000105e2d3 <+51>: mov 0x18(%rsp),%rbp
0x000000000105e2d8 <+56>: add $0x20,%rsp
0x000000000105e2dc <+60>: ret
0x000000000105e2dd <+61>: nopl (%rax)
0x000000000105e2e0 <+64>: call 0x1059560 <runtime.morestack_noctxt>
0x000000000105e2e5 <+69>: jmp 0x105e2a0 <main.main>
End of assembler dump.
(gdb) i r rbp rsp rip // Check the values of these registers
rbp 0xc0000507d0 0xc0000507d0
rsp 0xc000050780 0xc000050780
rip 0x105e2a0 0x105e2a0 <main.main>
(gdb)
Copy the code
The stack frame for main is as follows:
At this time, it only stops in the first line of main assembly code, but has not executed this line. Therefore, RIP stores the address of this line of code, and the CPU will execute the next instruction. Go straight down and break to line 7
(gdb) b *0x000000000105e2bd
Breakpoint 2 at 0x105e2bd
(gdb) c
Continuing.
Thread 2 hit Breakpoint 2.0x000000000105e2bd in main.main ()
(gdb) disas
Dump of assembler code for function main.main:
0x000000000105e2a0 <+0>: mov %gs:0x30,%rcx
0x000000000105e2a9 <+9>: cmp 0x10(%rcx),%rsp
0x000000000105e2ad <+13>: jbe 0x105e2e0 <main.main+64>
0x000000000105e2af <+15>: sub $0x20,%rsp
0x000000000105e2b3 <+19>: mov %rbp,0x18(%rsp)
0x000000000105e2b8 <+24>: lea 0x18(%rsp),%rbp
=> 0x000000000105e2bd <+29>: movq $0x1,(%rsp)
0x000000000105e2c5 <+37>: movq $0x2.0x8(%rsp)
0x000000000105e2ce <+46>: call 0x105e260 <main.sum>
0x000000000105e2d3 <+51>: mov 0x18(%rsp),%rbp
0x000000000105e2d8 <+56>: add $0x20,%rsp
0x000000000105e2dc <+60>: ret
0x000000000105e2dd <+61>: nopl (%rax)
0x000000000105e2e0 <+64>: call 0x1059560 <runtime.morestack_noctxt>
0x000000000105e2e5 <+69>: jmp 0x105e2a0 <main.main>
End of assembler dump.
(gdb) i r rbp rsp rip
rbp 0xc000050778 0xc000050778
rsp 0xc000050760 0xc000050760
rip 0x105e2bd 0x105e2bd <main.main+29>
(gdb)
Copy the code
Since main needs to supply sum with arguments and return values, main reserves 32 bytes of space (sizeof a + b + return value = 32), so in line 4, Sub moves RSP down by 32 bytes. Line 5 puts the contents of RBP at the position offset 24 bytes upward by RSP (plan9 is 24(SP)). Line 6 stores the address of 24(RSP) in RBP, which points to 24(RSP).
The stack frame for main is as follows:
Break point to call point
(gdb) b *0x000000000105e2ce
Breakpoint 3 at 0x105e2ce
(gdb) c
Continuing.
Thread 2 hit Breakpoint 3.0x000000000105e2ce in main.main ()
(gdb) disas
Dump of assembler code for function main.main:
0x000000000105e2a0 <+0>: mov %gs:0x30,%rcx
0x000000000105e2a9 <+9>: cmp 0x10(%rcx),%rsp
0x000000000105e2ad <+13>: jbe 0x105e2e0 <main.main+64>
0x000000000105e2af <+15>: sub $0x20,%rsp
0x000000000105e2b3 <+19>: mov %rbp,0x18(%rsp)
0x000000000105e2b8 <+24>: lea 0x18(%rsp),%rbp
0x000000000105e2bd <+29>: movq $0x1,(%rsp)
0x000000000105e2c5 <+37>: movq $0x2.0x8(%rsp)
=> 0x000000000105e2ce <+46>: call 0x105e260 <main.sum>
0x000000000105e2d3 <+51>: mov 0x18(%rsp),%rbp
0x000000000105e2d8 <+56>: add $0x20,%rsp
0x000000000105e2dc <+60>: ret
0x000000000105e2dd <+61>: nopl (%rax)
0x000000000105e2e0 <+64>: call 0x1059560 <runtime.morestack_noctxt>
0x000000000105e2e5 <+69>: jmp 0x105e2a0 <main.main>
End of assembler dump.
(gdb) i r rbp rsp rip
rbp 0xc000050778 0xc000050778
rsp 0xc000050760 0xc000050760
rip 0x105e2ce 0x105e2ce <main.main+46>
(gdb)
Copy the code
Movq $0x1,(% RSP) and MOVQ $0x2,0x8(% RSP) place 1 and 2 in RSP and 8(RSP), respectively, as arguments to sum. The stack frame for main is as follows:
Now it’s time to run the Call directive: Take a quick glancesum
function
(gdb) disas 'main.sum'
Dump of assembler code for function main.sum:
0x000000000105e260 <+0>: sub $0x10,%rsp
0x000000000105e264 <+4>: mov %rbp,0x8(%rsp)
0x000000000105e269 <+9>: lea 0x8(%rsp),%rbp
0x000000000105e26e <+14>: movq $0x0.0x28(%rsp)
0x000000000105e277 <+23>: mov 0x18(%rsp),%rax
0x000000000105e27c <+28>: add 0x20(%rsp),%rax
0x000000000105e281 <+33>: mov %rax,(%rsp)
0x000000000105e285 <+37>: mov %rax,0x28(%rsp)
0x000000000105e28a <+42>: mov 0x8(%rsp),%rbp
0x000000000105e28f <+47>: add $0x10,%rsp
0x000000000105e293 <+51>: ret
0x000000000105e294 <+52>: int3
0x000000000105e295 <+53>: int3
0x000000000105e296 <+54>: int3
0x000000000105e297 <+55>: int3
0x000000000105e298 <+56>: int3
0x000000000105e299 <+57>: int3
0x000000000105e29a <+58>: int3
0x000000000105e29b <+59>: int3
0x000000000105e29c <+60>: int3
0x000000000105e29d <+61>: int3
0x000000000105e29e <+62>: int3
0x000000000105e29f <+63>: int3
End of assembler dump.
(gdb) b *0x000000000105e260
Breakpoint 4 at 0x105e260
(gdb) disas
Dump of assembler code for function main.main:
0x000000000105e2a0 <+0>: mov %gs:0x30,%rcx
0x000000000105e2a9 <+9>: cmp 0x10(%rcx),%rsp
0x000000000105e2ad <+13>: jbe 0x105e2e0 <main.main+64>
0x000000000105e2af <+15>: sub $0x20,%rsp
0x000000000105e2b3 <+19>: mov %rbp,0x18(%rsp)
0x000000000105e2b8 <+24>: lea 0x18(%rsp),%rbp
0x000000000105e2bd <+29>: movq $0x1,(%rsp)
0x000000000105e2c5 <+37>: movq $0x2.0x8(%rsp)
=> 0x000000000105e2ce <+46>: call 0x105e260 <main.sum>
0x000000000105e2d3 <+51>: mov 0x18(%rsp),%rbp
0x000000000105e2d8 <+56>: add $0x20,%rsp
0x000000000105e2dc <+60>: ret
0x000000000105e2dd <+61>: nopl (%rax)
0x000000000105e2e0 <+64>: call 0x1059560 <runtime.morestack_noctxt>
0x000000000105e2e5 <+69>: jmp 0x105e2a0 <main.main>
End of assembler dump.
(gdb) i r rbp rsp rip
rbp 0xc000050778 0xc000050778
rsp 0xc000050760 0xc000050760
rip 0x105e2ce 0x105e2ce <main.main+46>
(gdb) c
Continuing.
Thread 2 hit Breakpoint 4.0x000000000105e260 in main.sum ()
(gdb) disas
Dump of assembler code for function main.sum:
=> 0x000000000105e260 <+0>: sub $0x10,%rsp
0x000000000105e264 <+4>: mov %rbp,0x8(%rsp)
0x000000000105e269 <+9>: lea 0x8(%rsp),%rbp
0x000000000105e26e <+14>: movq $0x0.0x28(%rsp)
0x000000000105e277 <+23>: mov 0x18(%rsp),%rax
0x000000000105e27c <+28>: add 0x20(%rsp),%rax
0x000000000105e281 <+33>: mov %rax,(%rsp)
0x000000000105e285 <+37>: mov %rax,0x28(%rsp)
0x000000000105e28a <+42>: mov 0x8(%rsp),%rbp
0x000000000105e28f <+47>: add $0x10,%rsp
0x000000000105e293 <+51>: ret
0x000000000105e294 <+52>: int3
0x000000000105e295 <+53>: int3
0x000000000105e296 <+54>: int3
0x000000000105e297 <+55>: int3
0x000000000105e298 <+56>: int3
0x000000000105e299 <+57>: int3
0x000000000105e29a <+58>: int3
0x000000000105e29b <+59>: int3
0x000000000105e29c <+60>: int3
0x000000000105e29d <+61>: int3
0x000000000105e29e <+62>: int3
0x000000000105e29f <+63>: int3
End of assembler dump.
(gdb) i r rbp rsp rip
rbp 0xc000050778 0xc000050778
rsp 0xc000050758 0xc000050758
rip 0x105e260 0x105e260 <main.sum>
(gdb)
Copy the code
When a call is executed, the rip value is programmed at 0x000000000105e2D3 for the next instruction, and the call pushes the current RIP value onto the stack (this represents the return ADDR position on the function stack). The RSP at the top of the stack is also moved down to the return ADDR position. At the same time, rip is set to the position of the first instruction of the function called by call 0x000000000105e260.
Continue to performsum
.
(gdb) b *0x000000000105e26e
Breakpoint 5 at 0x105e26e
(gdb) c
Continuing.
Thread 2 hit Breakpoint 5.0x000000000105e26e in main.sum ()
(gdb) disas
Dump of assembler code for function main.sum:
0x000000000105e260 <+0>: sub $0x10,%rsp
0x000000000105e264 <+4>: mov %rbp,0x8(%rsp)
0x000000000105e269 <+9>: lea 0x8(%rsp),%rbp
=> 0x000000000105e26e <+14>: movq $0x0.0x28(%rsp)
0x000000000105e277 <+23>: mov 0x18(%rsp),%rax
0x000000000105e27c <+28>: add 0x20(%rsp),%rax
0x000000000105e281 <+33>: mov %rax,(%rsp)
0x000000000105e285 <+37>: mov %rax,0x28(%rsp)
0x000000000105e28a <+42>: mov 0x8(%rsp),%rbp
0x000000000105e28f <+47>: add $0x10,%rsp
0x000000000105e293 <+51>: ret
0x000000000105e294 <+52>: int3
0x000000000105e295 <+53>: int3
0x000000000105e296 <+54>: int3
0x000000000105e297 <+55>: int3
0x000000000105e298 <+56>: int3
0x000000000105e299 <+57>: int3
0x000000000105e29a <+58>: int3
0x000000000105e29b <+59>: int3
0x000000000105e29c <+60>: int3
0x000000000105e29d <+61>: int3
0x000000000105e29e <+62>: int3
0x000000000105e29f <+63>: int3
End of assembler dump.
(gdb) i r rbp rsp rip
rbp 0xc000050750 0xc000050750
rsp 0xc000050748 0xc000050748
rip 0x105e26e 0x105e26e <main.sum+14>
(gdb)
Copy the code
Since the sum stack is not empty and there is only one local variable, it needs to be moved down 16 bytes (8 bytes for the local variable and 8 bytes for caller’s BP), and store the value of RBP into 8(RSP) and the address of 8(RSP) into RBP
The stack frame of main/sum is as follows:
Next five lines of assembly code
= >0x000000000105e26e <+14>: movq $0x0.0x28(%rsp)
0x000000000105e277 <+23>: mov 0x18(%rsp),%rax
0x000000000105e27c <+28>: add 0x20(%rsp),%rax
0x000000000105e281 <+33>: mov %rax,(%rsp)
0x000000000105e285 <+37>: mov %rax,0x28(%rsp)
Copy the code
- will
40(rsp)
The position of is assigned to0
- will
24(rsp)
The value of theta, which is theta1
enduresrax
In the - will
32(rsp)
The value of theta, which is theta2
, andrax
Add, and save the result torax
At this time,rax
The value of3
- will
rax
Assigns the value torsp
Local variablesc
) - will
rax
Assigns the value to40(rsp)
And this position representssum
The return value of the function
The stack frame of main/sum is as follows:
Continue execution, break point tosum
theret
place
(gdb) b *0x000000000105e293
Breakpoint 6 at 0x105e293
(gdb) c
Continuing.
Thread 2 hit Breakpoint 6.0x000000000105e293 in main.sum ()
(gdb) disas
Dump of assembler code for function main.sum:
0x000000000105e260 <+0>: sub $0x10,%rsp
0x000000000105e264 <+4>: mov %rbp,0x8(%rsp)
0x000000000105e269 <+9>: lea 0x8(%rsp),%rbp
0x000000000105e26e <+14>: movq $0x0.0x28(%rsp)
0x000000000105e277 <+23>: mov 0x18(%rsp),%rax
0x000000000105e27c <+28>: add 0x20(%rsp),%rax
0x000000000105e281 <+33>: mov %rax,(%rsp)
0x000000000105e285 <+37>: mov %rax,0x28(%rsp)
0x000000000105e28a <+42>: mov 0x8(%rsp),%rbp
0x000000000105e28f <+47>: add $0x10,%rsp
=> 0x000000000105e293 <+51>: ret
0x000000000105e294 <+52>: int3
0x000000000105e295 <+53>: int3
0x000000000105e296 <+54>: int3
0x000000000105e297 <+55>: int3
0x000000000105e298 <+56>: int3
0x000000000105e299 <+57>: int3
0x000000000105e29a <+58>: int3
0x000000000105e29b <+59>: int3
0x000000000105e29c <+60>: int3
0x000000000105e29d <+61>: int3
0x000000000105e29e <+62>: int3
0x000000000105e29f <+63>: int3
End of assembler dump.
(gdb) i r rbp rsp rip
rbp 0xc000050778 0xc000050778
rsp 0xc000050758 0xc000050758
rip 0x105e293 0x105e293 <main.sum+51>
(gdb)
Copy the code
Read these two lines
0x000000000105e28a <+42>: mov 0x8(%rsp),%rbp
0x000000000105e28f <+47>: add $0x10,%rsp
Copy the code
- will
8(rsp)
Assigns the value torbp
rsp
Move up 16 bytes
The stack frame for main is as follows: In the implementationret
Time,ret
thersp
Fetch the contents of the rip register, andreturn addr
Out of the stack,rsp
We move up 8 bytes, like thatrip
That points to the callsum
beforecall
The next address of the instruction, thus returning tomain
Function to continue executionThe stack frame for main is as follows:
Break to the next line of the call instruction
(gdb) b *0x000000000105e2d3
Breakpoint 7 at 0x105e2d3
(gdb) c
Continuing.
Thread 2 hit Breakpoint 7.0x000000000105e2d3 in main.main ()
(gdb) disas
Dump of assembler code for function main.main:
0x000000000105e2a0 <+0>: mov %gs:0x30,%rcx
0x000000000105e2a9 <+9>: cmp 0x10(%rcx),%rsp
0x000000000105e2ad <+13>: jbe 0x105e2e0 <main.main+64>
0x000000000105e2af <+15>: sub $0x20,%rsp
0x000000000105e2b3 <+19>: mov %rbp,0x18(%rsp)
0x000000000105e2b8 <+24>: lea 0x18(%rsp),%rbp
0x000000000105e2bd <+29>: movq $0x1,(%rsp)
0x000000000105e2c5 <+37>: movq $0x2.0x8(%rsp)
0x000000000105e2ce <+46>: call 0x105e260 <main.sum>
=> 0x000000000105e2d3 <+51>: mov 0x18(%rsp),%rbp
0x000000000105e2d8 <+56>: add $0x20,%rsp
0x000000000105e2dc <+60>: ret
0x000000000105e2dd <+61>: nopl (%rax)
0x000000000105e2e0 <+64>: call 0x1059560 <runtime.morestack_noctxt>
0x000000000105e2e5 <+69>: jmp 0x105e2a0 <main.main>
End of assembler dump.
(gdb) i r rbp rsp rip
rbp 0xc000050778 0xc000050778
rsp 0xc000050760 0xc000050760
rip 0x105e2d3 0x105e2d3 <main.main+51>
(gdb)
Copy the code
You can see that all of these registers have the same values as in the picture and then the next three lines of code
= >0x000000000105e2d3 <+51>: mov 0x18(%rsp),%rbp
0x000000000105e2d8 <+56>: add $0x20,%rsp
0x000000000105e2dc <+60>: ret
Copy the code
- Put the value of 24(RSP) into RBP
- Move RSP up 32 bytes
- Ret returns the calling function of main
The stack frame of the function is as follows: