先看源码
package main //!+f func main() { f1() f2() f3() } func f1() (result int) { defer func() { result++ }() return 0 } func f2() (r int) { t := 5 defer func() { t = t + 5 }() return t } func f3() (r int) { defer func(r int) { r = r + 5 }(r) return 1 }
再看反汇编代码
000000000044c320 <main.f1.func1>: 44c320: 48 8b 44 24 08 mov 0x8(%rsp),%rax 44c325: 48 ff 00 incq (%rax) 44c328: c3 retq 44c329: cc int3 44c32a: cc int3 44c32b: cc int3 44c32c: cc int3 44c32d: cc int3 44c32e: cc int3 44c32f: cc int3 000000000044c330 <main.f2.func1>: 44c330: 48 8b 44 24 08 mov 0x8(%rsp),%rax 44c335: 48 83 00 05 addq $0x5,(%rax) 44c339: c3 retq 44c33a: cc int3 44c33b: cc int3 44c33c: cc int3 44c33d: cc int3 44c33e: cc int3 44c33f: cc int3 000000000044c340 <main.f3.func1>: 44c340: c3 retq 44c341: cc int3 44c342: cc int3 44c343: cc int3 44c344: cc int3 44c345: cc int3 44c346: cc int3 44c347: cc int3 44c348: cc int3 44c349: cc int3 44c34a: cc int3 44c34b: cc int3 44c34c: cc int3 44c34d: cc int3 44c34e: cc int3 44c34f: cc int3
那么多的 int3 是为了保证函数栈是对齐的? yes it is ! some compiler use nop, others use int3 !
000000000044c150 <main.main>: 44c150: 64 48 8b 0c 25 f8 ff mov %fs:0xfffffffffffffff8,%rcx 44c157: ff ff 44c159: 48 3b 61 10 cmp 0x10(%rcx),%rsp 44c15d: 76 27 jbe 44c186 <main.main+0x36> 44c15f: 48 83 ec 10 sub $0x10,%rsp 44c163: 48 89 6c 24 08 mov %rbp,0x8(%rsp) 44c168: 48 8d 6c 24 08 lea 0x8(%rsp),%rbp 44c16d: e8 1e 00 00 00 callq 44c190 <main.f1> 44c172: e8 99 00 00 00 callq 44c210 <main.f2> 44c177: e8 24 01 00 00 callq 44c2a0 <main.f3> 44c17c: 48 8b 6c 24 08 mov 0x8(%rsp),%rbp 44c181: 48 83 c4 10 add $0x10,%rsp 44c185: c3 retq 44c186: e8 e5 83 ff ff callq 444570 <runtime.morestack_noctxt> 44c18b: eb c3 jmp 44c150 <main.main> 44c18d: cc int3 44c18e: cc int3 44c18f: cc int3
为什么大部分的函数都是先 mov,cmp, jbe 到 runtime.morestack_noctxt 那里? 据说和连续栈有关,而且还涉及到黑科技!留给以后研究