Go语言汇编

Plan 9汇编

寄存器:

数据寄存器:R0-R7,地址寄存器:A0-A7,浮点寄存器:F0-F7。

伪栈寄存器:FP, SP, TOS。

FP是frame pointer,0(FP)是第一个参数,4(FP)是第二个。

SP是local stack pointer,保存自动变量。0(SP)是第一个。

TOS是top of stack寄存器,用来保存过程的参数,保存局部变量。

汇编器可以有一个变量名,比如p+0(FP),表示p是第一个参数,这个变量保存在符号表内,但是对程序运行没有影响。

数据:

所有的外部引用都需通过伪寄存器: PC(virtual Program Counter)/SB(Static Base register)。

PC用来控制程序执行,SB用来引用全局变量。比如:

把全局数组的地址压栈:MOVL $array(SB), TOS。

把全局数组的第二个元素压栈:MOVL array+4(SB), TOS

local<>+4(SB)是本地变量,只在本文件可见。

定义流程:

TEXT sum(SB), $0

TEXT是一个伪指令,用来定义入口点。后面的参数是函数名,然后是栈大小,通常为0。

中间可以有一个指定loader的选项,设置为1暂停函数的profiling。

设置为2允许一个程序中有多个TEXT符号。

子流程把运算结果放到R0中。浮点的结果放在F0中。

子流程负责保存自己的寄存器,为caller saves模式。

 Go语言汇编

Go语言的汇编基于Plan 9的汇编,但是有一些不同。最主要的一个区别是,Go语言的汇编指令不一定直接对应机器表示。有一些直接对应,有一些则不是。

编译器产生的是一些中间码,具体的机器指令是在汇编生成之后才定下来的(Linker的工作)。

FUNCDATA和PCDATA是编译器产生的,用于保存一些给垃圾收集的信息。

Go语言的汇编和Plan 9的另一个不同是操作符的优先级。比如3&1<<2被解释成(3&1)<<2。

符号:

Go语言有4个伪寄存器,实际是对内存位置的一个引用。

FP: 帧指针,保存参数和本地变量

PC:程序指针,负责跳转和流程控制

SB: 静态基指针,全局变量

SP:栈指针,栈顶

所有的符号全部携程FP和SB的偏移的形式:

SB伪寄存器用来表示全局的变量或者函数,不如foo(SB)用来表示foo的地址。加<>表示符号本文件内可见。

FP是用来保存参数的。(0)FP是第一个参数(8)FP是第二个(如果是64位机器)。

SP指向本地栈顶,分别用x-8(SP), y-4(SP)表示变量。

直接的jmp或者call指令,只能指向text符号,不能是符号的偏移。

指令:

TEXT指令定义一个符号,后面紧跟函数体。

DATA指令定义一个section的内存,这段内存并不会被初始化。

DATA    symbol+offset(SB)/width, value

GLOBAL指令定义一个符号是全局的

GLOBL divtab<>(SB), RODATA, $64

GLOBL runtime·tlsoffset(SB), NOPTR, $4

divtab是制度的64byte的表格,保存4个byte的整形。tlsoffset是,4byte的no pointers

指令修饰符:

DUPOK:允许一个二进制文件里有多个实例

NOSPLIT: FOR TEXT,routine或者routine的子函数,必须把栈的空间的头填满,用来保护栈分隔

RODATA:FOR DATA/GLOBL,把数据放在只读段

NOPTR: FOR DATA/GLOBL,数据没有指针,不需要被垃圾收集扫描

WRAPPER: FOR TEXT,wrapper function,不需要被以禁用recover计数

NEEDCTXT:FOR TEXT,闭包

Runtime协作:

NOPTR和RODATA的数据不需要被垃圾收集。比指针还要小的数据也被当做NOPTR。不要在go汇编里写非只读数据。

语法:

plan9函数调用协议中采用的是caller-save的模式,也就是由调用者负责保存寄存器。

TEXT !$Add(SB),$0
    MOVQ x+0(FP), BX
    MOVQ y+8(FP), BP
    ADDQ BP, BX
    MOVQ BX, ret+16(FP)
    RET

a+8(FP)

变量名+偏移(寄存器)。FP其实就是BP(栈基址寄存器上移一个机器字长位置的内存地址)。

TEXT ·add(SB),NOSPLIT,$0

00B7分隔了包名和变量名。NOSPLIT表示不用写入参数的大小,$0表示参数的大小,因为制定了NOSPLIT所以写0

汇编文件的名字甚至变量名称并不重要。

MOVQ $0, DX //put 0 into DX register. Q means quadword which is 8 bytes. L for 4 bytes. (src, destination) order

¥24-8表示24字节的帧,和8个字节的参数

Go Array有不是指向第一个元素的指针,而是代表整个数组。赋值或者传递的时候是有一个copy的。

Go slice有三个部分, 一个指针,一个长度,一个容量,指针8个字节,长度和容量4个字节

一个slice没有固定的长度。slice不能指定长度。一个slice如果要增加capacity必须创建一个新的容量更大的slice,并copy内容过去。

Examples:

原文地址:https://www.cnblogs.com/dracohan/p/6405695.html