Quick start of Golang assembly

@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.gooutput 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

Insert picture description here
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:
Insert picture description here

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

Guess you like

Origin blog.csdn.net/qq_17818281/article/details/114891093