diff --git a/ch3-asm/ch3-02-arch.md b/ch3-asm/ch3-02-arch.md index 74fadf1..5bc59f6 100644 --- a/ch3-asm/ch3-02-arch.md +++ b/ch3-asm/ch3-02-arch.md @@ -140,3 +140,17 @@ Go汇编为了简化汇编代码的编写,引入了PC、FP、SP、SB四个伪 当需要区分伪寄存器和真寄存器的时候只需要记住一点:伪寄存器一般需要一个标识符和偏移量为前缀,如果没有标识符前缀则是真寄存器。比如`(SP)`、`+8(SP)`没有标识符前缀为真SP寄存器,而`a(SP)`、`b+8(SP)`有标识符为前缀表示伪寄存器。 + +## Go函数调用规范 + +和C语言函数不同,Go语言函数的参数和返回值完全通过栈传递。下面是Go函数调用时栈的布局图: + +![](../images/ch3-func-stack-frame-layout-01.ditaa.png) + +在汇编定义函数时,我们需要关注framesize和argsize,分别对应函数帧大学和函数参数和返回值的大小。 + +因为函数的参数和返回大学可以通过Go函数的签名解析得到,因此argsize一般是可以省略的。需要注意的是,输入参数和返回值依此从低地址向高地址顺序排列。同时每个参数的类型需要满足地址对齐要求。 + +帧大小相对复杂一点:其中包含函数的局部变量和调用其它函数时的参数和返回值空间。局部变量也是从低地址向高地址顺序排列的,因此它们栈增长方向是相反的。 + +在最下面灰色的部分是调用函数后的返回地址。当执行CALL指令时,会自动将SP向下移动,并将返回地址和SP寄存器存入栈中。然后被调用的函数执行RET返回指令时,先从栈恢复BP和SP寄存器,并根取出的返回地址跳转到对应的指令执行。 diff --git a/images/ch3-func-stack-frame-layout-01.ditaa.png b/images/ch3-func-stack-frame-layout-01.ditaa.png new file mode 100644 index 0000000..bf090d8 Binary files /dev/null and b/images/ch3-func-stack-frame-layout-01.ditaa.png differ diff --git a/images/ch3-func-stack-frame-layout-01.ditaa.txt b/images/ch3-func-stack-frame-layout-01.ditaa.txt new file mode 100644 index 0000000..0fb7a9b --- /dev/null +++ b/images/ch3-func-stack-frame-layout-01.ditaa.txt @@ -0,0 +1,63 @@ + Stack frame layout X86/AMD64 + + ---=- +-=-------------------------+ + ^ | | + | | ret1 to caller | + | | | + | +-=-------------------------+<--ret1+24(FP) + | | | + : | ret0 to caller | + | | + argsize +-=-------------------------+<--ret0+16(FP) + | | + : | arg1 from caller | + | | | + | +-=-------------------------+<--arg1+8(FP) + | | | + | | arg0 from caller | + v | | + ---=- +-=-------------------------+<--arg0+0(FP) + | | + | parent return address | + | | + +---------------------------+ + | c9D5 | + | caller's BP | + | (if framepointer_enabled) | + ---=- +---------------------------+<--BP(pseudo SP) + ^ | cD0A | + | | local varable2 | + | | | + | +---------------------------+<--var2-8(SP) + | | cD0A | + | | local varable1 | + | | | + | +---------------------------+<--var1-16(SP) + | | cD0A | + | | local varable0 | + | | | + | +---------------------------+<--var0-24(SP) + : | cYEL | + | | ret1 from callee | + | | + framesize+---------------------------+<--24(SP) + | cYEL | + | | ret0 from callee | + : | | + | +---------------------------+<--16(SP) + | | cF51 | + | | arg1 to callee | + | | | + | +---------------------------+<--8(SP) + | | cF51 | + | | arg0 to callee | + v | | + ---=- +---------------------------+<--0(SP) + | cAAA | + | return address | + | | + +---------------------------+ + | cAAA | + | caller's BP | + | (if framepointer_enabled) | + +---------------------------+