This is a creation in Article, where the information may have evolved or changed.
Derived from the PLAN9 assembly implementation. Saved in the. s file, the compiler compiles and links automatically.
The content of this article is based on AMD64 architecture.
Instructions
Instruction parameter length.
Data movement direction: from left to right.
ADD R1, R2 // R2 += R1 SUB R3, R4 // R4 -= R3 SUB R3, R4, R5 // R5 = R4 - R3 MUL $7, R6 // R6 *= 7
Memory access.
MOV (R1), R2 // R2 = *R1 MOV 8(R1), R2 // R2 = *(8 + R2) MOV 16(R1)(R2*2), R3 // R3 = *(16 + R1 + R2*2) MOV runtime·x(SB), R2 // R2 = *runtime·x
Jump instructions.
JMP label // 跳转到标签。 JMP 2(PC) // 跳转到 PC + n 行。 JMP -2(PC)
Numeric constants begin with $, decimal ($), and hexadecimal ($0x10). The label is valid only within the function.
Pseudo Register
Pseudo registers (Pseudo-register) are defined and used by the language and are eventually compiled into hardware register references.
Considering the platform differences, the compiled machine code may need to save the physical register values of PC, BP, SP, etc. When writing assembly code, it is difficult to calculate the actual required offsets beforehand. Therefore, it is necessary for assembly language to represent a relative position with pseudo register.
- Sb:static Base Pointer (global symbol) represents a global symbolic address, typically applied to global functions or data.
For example
CALL add(SB)
, a memory address that represents the name of add for the corresponding symbol.
Add angle brackets () after the name to add<>(SB)
indicate that the symbol name is visible only in the current file. An offset can also be used to represent an address based on a symbolic name, for example add+8(SB)
.
- Fp:frame Pointer (parameter address) points to the starting address of the parameter list provided by the caller, pointing to different parameters or return values by offset. The parameter name is usually included before the offset. For example
MOVQ size+16(FP), AX
- Sp:stack Pointer (stack local variable memory address) The pseudo SP register represents the starting address for local local variable operations within the stack frame.
Given how the stack starts at the bottom, the SP is actually the bottom position (equivalent to the adjusted BP address). To access a local variable using this method, you add a variable name, such as
x-8(SP)
. If the variable name is omitted, the hardware register is represented.
- Pc:program Counter (instruction address) can be used to follow the instruction line number of lines. For example
JMP 2(PC)
, the current position is the 0 datum, jumping down to line 2nd.
Considering that stack frame memory is actually divided into local variable (bottom) and call parameter (top) two parts, it is natural to use false SP register negative value to access local variables cheaply. Thus, the physical register SP is used to manipulate the call parameters into the stack, while the pseudo register SP is used to access local variables. After all, the BP register is optional.
Notice x+0(FP)
gobuf_pc(AX)
The difference from the macro function.
CALLEE Lo SP +-----------+ ... .............. ... | | . +-----------+ . | | Frame size (including caller BP) BP (pseudo SP) +-----------+. | Caller BP | . +-----------+ .......................... | Caller PC | FP +-----------+------------+ SP ..... | arg0 | Call Arg0 | . +-----------+------------+ . | argn | Call Argn | Argument size +-----------+------------+. | return | Call RET | . Hi +-----------+------------+ ....... | Local VAR0 | +------------+ | Local Varn | +------------+ BP (pseudo SP) CALLER
Function
function definition.
参数及返回值大小 | TEXT runtime·cgocallback(SB),NOSPLIT,$32-32 | | | 包名 函数名 栈帧大小(不包括参数及返回值)
The current package can omit the package name and begin directly with the center point.
The caller (caller) is responsible for assigning the target function (callee) parameter and the return value memory. The caller must save the relevant register state themselves.
Example
Write a simple addition using the assembly code.
Add.s
#include "textflag.h" // add(x, y int) int TEXT ·add(SB), NOSPLIT, $8-24 MOVQ $0, z-0x8(SP) MOVQ x+0x0(FP), AX MOVQ y+0x8(FP), BX ADDQ AX, BX MOVQ BX, z-0x8(SP) MOVQ BX, ret+0x10(FP) RET
Main.go
package main func add(x, y int) (z int) // 声明汇编函数原型 func main() { z := add(0x100, 0x200) println(z) }
You can see the compiler insert stack frame adjustment, environment preservation and other directives.
$ go build -gcflags "-l" $ go tool objdump -s "main\.add" test TEXT main.add(SB) add.s add.s:5 0x104bfe0 SUBQ $0x10, SP // 因为要保存 BP,所以栈帧大小调整到 0x10。 add.s:5 0x104bfe4 MOVQ BP, 0x8(SP) add.s:5 0x104bfe9 LEAQ 0x8(SP), BP add.s:6 0x104bfee MOVQ $0x0, 0(SP) add.s:7 0x104bff6 MOVQ 0x18(SP), AX add.s:8 0x104bffb MOVQ 0x20(SP), BX add.s:9 0x104c000 ADDQ AX, BX add.s:10 0x104c003 MOVQ BX, 0(SP) add.s:11 0x104c007 MOVQ BX, 0x28(SP) add.s:12 0x104c00c MOVQ 0x8(SP), BP add.s:12 0x104c011 ADDQ $0x10, SP // 清除栈帧。 add.s:12 0x104c015 RET
-gcflags -S
when using output disassembly, there are funcdata and PCDATA information. They are introduced by the compiler and contain information to be used by the garbage collector.
323 reads