diff --git a/ch3-asm/ch3-08-debug.md b/ch3-asm/ch3-08-debug.md index a9f5b2d..e333218 100644 --- a/ch3-asm/ch3-08-debug.md +++ b/ch3-asm/ch3-08-debug.md @@ -239,7 +239,19 @@ Goroutine 1: 用Delve调试Go汇编程序的过程比调试Go语言程序更加简单。调试汇编程序时,我们需要时刻关注寄存器的状态,如果涉及函数调用或局部变量或参数还需要重点关注栈寄存器SP的状态。 -为了编译演示,我们用汇编重新实现main函数,简单打印一个字符串: +为了编译演示,我们重新实现一个更简单的main函数: + +```go +package main + +func main() { asmSayHello() } + +func asmSayHello() +``` + +在main函数中调用汇编语言实现的asmSayHello函数输出一个字符串。 + +asmSayHello函数在main_amd64.s文件中实现: ``` #include "textflag.h" @@ -250,8 +262,8 @@ DATA text<>+0(SB)/8,$"Hello Wo" DATA text<>+8(SB)/8,$"rld!\n" GLOBL text<>(SB),NOPTR,$16 -// func main() -TEXT ·main(SB), $16-0 +// func asmSayHello() +TEXT ·asmSayHello(SB), $16-0 NO_LOCAL_POINTERS MOVQ $text<>+0(SB), AX MOVQ AX, (SP) @@ -260,19 +272,50 @@ TEXT ·main(SB), $16-0 RET ``` -然后依然用break命令在main函数设置断点,并且输入continue命令让调试器执行到断点位置停下: +参考前面的调试流程,在执行到main函数断点时,可以disassemble反汇编命令查看main函数对应的汇编代码: ``` (dlv) break main.main -Breakpoint 1 set at 0x105018f for main.main() ./main_amd64.s:10 +Breakpoint 1 set at 0x105011f for main.main() ./main.go:3 (dlv) continue -> main.main() ./main_amd64.s:10 (hits goroutine(1):1 total:1) (PC: 0x105018f) +> main.main() ./main.go:3 (hits goroutine(1):1 total:1) (PC: 0x105011f) + 1: package main + 2: +=> 3: func main() { asmSayHello() } + 4: + 5: func asmSayHello() +(dlv) disassemble +TEXT main.main(SB) /Users/chai/go/src/github.com/chai2010/advanced-go-programming-book/vendor/gobook.examples/ch3-08-debug/hello-asm/main.go + main.go:3 0x1050110 65488b0c25a0080000 mov rcx, qword ptr gs:[0x8a0] + main.go:3 0x1050119 483b6110 cmp rsp, qword ptr [rcx+0x10] + main.go:3 0x105011d 761a jbe 0x1050139 +=> main.go:3 0x105011f* 4883ec08 sub rsp, 0x8 + main.go:3 0x1050123 48892c24 mov qword ptr [rsp], rbp + main.go:3 0x1050127 488d2c24 lea rbp, ptr [rsp] + main.go:3 0x105012b e880000000 call $main.asmSayHello + main.go:3 0x1050130 488b2c24 mov rbp, qword ptr [rsp] + main.go:3 0x1050134 4883c408 add rsp, 0x8 + main.go:3 0x1050138 c3 ret + main.go:3 0x1050139 e87288ffff call $runtime.morestack_noctxt + main.go:3 0x105013e ebd0 jmp $main.main +(dlv) +``` + +虽然main函数内部只有一行函数调用语句,但是却生成了很多汇编指令。在函数的开头通过比较rsp寄存器判断栈空间是否不足,如果不足则跳转到0x1050139地址调用runtime.morestack函数进行栈扩容,然后跳回到main函数开始位置重新进行栈空间测试。而在asmSayHello函数调用之前,先扩展rsp空间用于临时存储rbp寄存器的状态,在函数返回后通过栈恢复rbp的值并回收临时栈空间。通过对比Go语言代码和对应的汇编代码,我们可以加深对Go汇编语言的理解。 + +从汇编语言角度深刻Go语言各种特性的工作机制对调试工作也是一个很大的帮助。现在我们依然用break命令在asmSayHello函数设置断点,并且输入continue命令让调试器执行到断点位置停下: + +``` +(dlv) break main.asmSayHello +Breakpoint 2 set at 0x10501bf for main.asmSayHello() ./main_amd64.s:10 +(dlv) continue +> main.asmSayHello() ./main_amd64.s:10 (hits goroutine(1):1 total:1) (PC: 0x10501bf) 5: DATA text<>+0(SB)/8,$"Hello Wo" 6: DATA text<>+8(SB)/8,$"rld!\n" 7: GLOBL text<>(SB),NOPTR,$16 8: - 9: // func main() -=> 10: TEXT ·main(SB), $16-0 + 9: // func asmSayHello() +=> 10: TEXT ·asmSayHello(SB), $16-0 11: NO_LOCAL_POINTERS 12: MOVQ $text<>+0(SB), AX 13: MOVQ AX, (SP) @@ -285,14 +328,14 @@ Breakpoint 1 set at 0x105018f for main.main() ./main_amd64.s:10 ``` (dlv) regs - rax = 0x0000000001050180 + rax = 0x0000000001050110 rbx = 0x0000000000000000 rcx = 0x000000c420000300 - rdx = 0x0000000001070bc0 + rdx = 0x0000000001070be0 rdi = 0x000000c42007c020 rsi = 0x0000000000000001 - rbp = 0x00007fffffe00000 - rsp = 0x000000c420049f80 + rbp = 0x000000c420049f78 + rsp = 0x000000c420049f70 r8 = 0x7fffffffffffffff r9 = 0xffffffffffffffff r10 = 0x0000000000000100 @@ -301,8 +344,8 @@ Breakpoint 1 set at 0x105018f for main.main() ./main_amd64.s:10 r13 = 0x0000000000000000 r14 = 0x0000000000000178 r15 = 0x0000000000000004 - rip = 0x000000000105018f - rflags = 0x0000000000000202 + rip = 0x00000000010501bf + rflags = 0x0000000000000206 ... (dlv) ``` diff --git a/vendor/gobook.examples/ch3-08-debug/hello-asm/main.go b/vendor/gobook.examples/ch3-08-debug/hello-asm/main.go index 9d143c0..7fcece9 100644 --- a/vendor/gobook.examples/ch3-08-debug/hello-asm/main.go +++ b/vendor/gobook.examples/ch3-08-debug/hello-asm/main.go @@ -1,7 +1,5 @@ -// Copyright 2018 . All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - package main -func main() +func main() { asmSayHello() } + +func asmSayHello() diff --git a/vendor/gobook.examples/ch3-08-debug/hello-asm/main_amd64.s b/vendor/gobook.examples/ch3-08-debug/hello-asm/main_amd64.s index 9fb9006..43200ca 100644 --- a/vendor/gobook.examples/ch3-08-debug/hello-asm/main_amd64.s +++ b/vendor/gobook.examples/ch3-08-debug/hello-asm/main_amd64.s @@ -6,8 +6,8 @@ DATA text<>+0(SB)/8,$"Hello Wo" DATA text<>+8(SB)/8,$"rld!\n" GLOBL text<>(SB),NOPTR,$16 -// func main() -TEXT ·main(SB), $16-0 +// func asmSayHello() +TEXT ·asmSayHello(SB), $16-0 NO_LOCAL_POINTERS MOVQ $text<>+0(SB), AX MOVQ AX, (SP)