@Golang Assembly Quick Start
plan9 basic instructions
Constants
Constants are represented by $num in plan9 assembly and can be negative numbers. By default, they are decimal. You can use the form of $0x123 to represent a hexadecimal number.
Stack adjustment
Intel or AT&T assembler provides push and pop instruction families. There is no push and pop in plan9. Stack adjustment is realized by performing operations on hardware SP registers, for example:
SUBQ $20, SP // 对 SP 做减法,为函数分配函数栈帧
ADDQ $20, SP // 对 SP 做加法,清除函数栈帧
Data handling
The length of the handling is determined by the suffix of MOV. The direction of the operand is opposite to intel assembly, and the left value is assigned to the right value (in general)
MOVB $1, AX // 1 byte
MOVW $1, AX // 2 bytes
MOVD $1, AX // 4 bytes
MOVQ $1, AX // 8 bytes
Address calculation
Address calculation also uses lea instruction, amd64 platform address is 8 bytes, so directly use LEAQ
LEAQ 4(AX), AX
Don’t introduce the others too much
Golang and plan9, must see
The Go compilation also introduces 4 pseudo-registers, citing the description of the official document:
- FP: Frame pointer: arguments and locals.
- PC: Program counter: jumpsand branches.
- SB: Static base pointer: global symbols.
- SP: Stack pointer: top of stack. It
has little effect on looking at the assembly code of golang. I will not introduce too much here. The reason why it is proposed is because there are pits
for the compilation output (go tool compile -S / go tool objdump). In terms of code, all current SPs are hardware registers SP, so the pseudo SP basically has no effect. The compiled assembly code is only BP and SP
Text, simply give a chestnut
test.go在这里插入代码片
package main
func main() {
a1:= add(3, 2)
b1:= add(6,4)
a1=a1+b1
}
func add(a, b int) int {
return a+b
}
To use the go tool compile -S -N .\test.go
output assembly code, be sure to add -N, do not optimize, otherwise you can see the
output of the Mongolian (with abridged)
comments only provide a brief description, will be introduced in detail later
"".main STEXT nosplit size=131 args=0x0 locals=0x58 funcid=0x0
0x0000 00000 (.\test.go:3) TEXT "".main(SB), NOSPLIT|ABIInternal, $88-0 // 定义函数
0x0000 00000 (.\test.go:3) SUBQ $88, SP // 移动SP,分配栈空间
0x0004 00004 (.\test.go:3) MOVQ BP, 80(SP) // 保存调用者BP
0x0009 00009 (.\test.go:3) LEAQ 80(SP), BP // 移动BP
0x000e 00014 (.\test.go:3) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x000e 00014 (.\test.go:3) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x000e 00014 (.\test.go:4) MOVQ $3, "".a+48(SP) // 对第一次add()的传入参数a赋值
0x0017 00023 (.\test.go:4) MOVQ $2, "".b+24(SP) // 同上
0x0020 00032 (<unknown line number>) NOP
0x0020 00032 (.\test.go:10) MOVQ "".a+48(SP), AX // 这里事实上是在add()里的计算过程
0x0025 00037 (.\test.go:10) ADDQ $2, AX // 将计算结果保存到AX里
0x0029 00041 (.\test.go:4) MOVQ AX, ""..autotmp_8+72(SP) // 临时变量,目前还为理解意义在哪
0x002e 00046 (.\test.go:4) MOVQ AX, "".~R0+8(SP) // 将结果传给返回值 也就是 add() int 的int
0x0033 00051 (.\test.go:4) JMP 53 //跳到53
0x0035 00053 (.\test.go:4) MOVQ AX, "".a1+40(SP) // 第二次add()调用 不做解释
0x003a 00058 (.\test.go:5) MOVQ $6, "".a+56(SP)
0x0043 00067 (.\test.go:5) MOVQ $4, "".b+32(SP)
0x004c 00076 (<unknown line number>) NOP
0x004c 00076 (.\test.go:10) MOVQ "".a+56(SP), AX
0x0051 00081 (.\test.go:10) LEAQ 4(AX), CX // 这里是利用LEQ实现计算
0x0055 00085 (.\test.go:5) MOVQ CX, ""..autotmp_9+64(SP)
0x005a 00090 (.\test.go:5) MOVQ CX, "".~R0(SP)
0x005e 00094 (.\test.go:5) NOP
0x0060 00096 (.\test.go:5) JMP 98
0x0062 00098 (.\test.go:5) MOVQ CX, "".b1+16(SP) // a1= a1 + b1的计算过程
0x0067 00103 (.\test.go:6) MOVQ "".a1+40(SP), CX
0x006c 00108 (.\test.go:6) LEAQ (AX)(CX*1), AX
0x0070 00112 (.\test.go:6) LEAQ 4(AX), AX
0x0074 00116 (.\test.go:6) MOVQ AX, "".a1+40(SP) // 将计算结果赋值给a1
0x0079 00121 (.\test.go:7) MOVQ 80(SP), BP // 移动BP
0x007e 00126 (.\test.go:7) ADDQ $88, SP // 缩减栈
0x0082 00130 (.\test.go:7) RET // 返回
"".add STEXT nosplit size=25 args=0x18 locals=0x0 funcid=0x0
0x0000 00000 (.\test.go:9) TEXT "".add(SB), NOSPLIT|ABIInternal, $0-24
0x0000 00000 (.\test.go:9) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x0000 00000 (.\test.go:9) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x0000 00000 (.\test.go:9) MOVQ $0, "".~r2+24(SP) // 给返回值赋初值
0x0009 00009 (.\test.go:10) MOVQ "".a+8(SP), AX
0x000e 00014 (.\test.go:10) ADDQ "".b+16(SP), AX
0x0013 00019 (.\test.go:10) MOVQ AX, "".~r2+24(SP) // 将结果赋值给返回值
0x0018 00024 (.\test.go:10) RET // 返回
TEXT "".main(SB), NOSPLIT|ABIInternal, $88-0
TEXT symbol(SB), [flags,] $framesize[-argsize]
TEXT is used to define the function symbol
symbol. The function name symbol is composed of the package name and the function name. The package name can be omitted. SB means the function name symbol is relative to the SB pseudo-register The offset of the two is combined and finally the absolute address
flags is used to indicate some special behavior of the function. The common NOSPLIT is mainly used to indicate that the leaf function does not perform stack splitting.
framesize indicates how much stack space is needed for the local variables of the function, including calls The implicit stack space
argsize that prepares to call parameters for other functions indicates the size of function parameters, including incoming parameters and return values
Stack frame analysis
mian()
To tell the truth, I don’t understand the stack frame of main() too much. It may be caused by the function call. What is the meaning of autotmp and ~R0? When I understand that day, let me add it. , Forgive me for being a little kid
add()
TEXT "".add(SB), NOSPLIT|ABIInternal, $0-24
Add() has no local variables, so the framesize is 0, and there are 3 parameters, so the argsize is 24.
Stack structure
The following is a stack structure diagram of a typical function:
args: The memory arrangement of the parameter part is the high address of the variable that appears later, that is, the corresponding from left to right from top to bottom.
Caller BP: Stores the BP of the calling function.
Frame: Stores local variables, which are taken by local variables. The memory arrangement method is to take
photos from top to bottom in ascending order of variable names. return addr: return address, that is, the calling location
If you are helpful, you can like it. If you like it, you can bookmark it. I write less blog. I'm about to interview. I want to get something out of my hand. Hahahaha. Recently, I will write out some things I have encountered, what I learned Will also share