登录 用户中心() [退出] 后台管理 注册
   
您的位置: 首页 >> SoftHub关联区 >> 主题: [golang]Golang中的Plan9汇编器[zt]     [回主站]     [分站链接]
[golang]Golang中的Plan9汇编器[zt]
clq
浏览(171) - 2023-04-23 10:45:04 发表 编辑

关键字:

https://blog.csdn.net/whatday/article/details/98179843

https://github.com/yangyuqian/technical-articles/blob/master/asm/golang-plan9-assembly-cn.md

Golang中的Plan9汇编器

Golang自1.4之后实现了自举,即用Go实现编译器来编译Go源码,从此 Go与机器之间只隔了一层汇编实现,本文中介绍Plan9汇编旨在进一步学习 Go编译做准备. Go中Plan9的实现和具体的系统架构无关,实现了汇编的跨平台, 下面以MACOS + Intel i7为例介绍.

为了区分Plan9汇编和Go Plan9 Assembler,下面所有的描述都会改为 Go Assembler.

Go Assembler中的虚拟寄存器:

FP(Frame pointer): arguments and locals.
PC(Program counter): jumps and branches.
SB(Static base pointer): global symbols.
SP(Stack pointer): top of stack.

// 所有用户空间的数据都可以通过FP(局部数据)或SB(全局数据)访问
All user-defined symbols are written as offsets to the pseudo-registers
FP (arguments and locals) and SB (globals).

// SB抽象了内存空间,foo(SB)的意思是用foo来代表内存里面的一个地址(赋值?)
The SB pseudo-register can be thought of as the origin of memory,
so the symbol foo(SB) is the name foo as an address in memory.
// foo(SB)可以用来定义全局的function和数据
This form is used to name global functions and data.
// foo<>(SB)和C里面的static一个效果,声明只在当前源码文件中可见
Adding <> to the name, as in foo<>(SB),
makes the name visible only in the current source file,
like a top-level static declaration in a C file.
// 可以在引用上加上偏移量,如前面说的foo(SB),
// 如果foo+4(SB)的意思是foo + 4 bytes的地址
Adding an offset to the name refers to that offset from the symbol's address,
so foo+4(SB) is four bytes past the start of foo.

// FP用来访问函数的参数
The FP pseudo-register is a virtual frame pointer used to
refer to function arguments.
// 编译器维护了栈上的参数指针
The compilers maintain a virtual frame pointer and refer to
the arguments on the stack as offsets from that pseudo-register.
// 0(FP)就是function的第一个参数
Thus 0(FP) is the first argument to the function,
// 64位系统上8(FP)就是第二个参数,后面加上偏移量就可以访问更多的参数
8(FP) is the second (on a 64-bit machine), and so on.
// 要访问具体function的参数,需要加上name,比如foo+0(FP)获取foo的第一个参数
// foo+8(FP)获取第二个参数
However, when referring to a function argument this way,
it is necessary to place a name at the beginning,
as in first_arg+0(FP) and second_arg+8(FP).
// 编译器中强制要求必须用name来访问FP
The assembler enforces this convention, rejecting plain 0(FP) and 8(FP).

// SP是栈指针,和NASM中的RSP类似
The SP pseudo-register is a virtual stack pointer used to refer to
frame-local variables and the arguments being prepared for function calls.
// SP指向当前local stack frame的栈顶,使用时foo-8(SP)代表foo的栈第8byte
It points to the top of the local stack frame,
so references should use negative offsets in the range
[−framesize, 0): x-8(SP), y-4(SP), and so on.]

// 如果硬件支持SP寄存器,那么不加name的时候就是访问硬件寄存器.
// 因此 x-8(SP)和-8(SP)访问的会是不同的内存空间
On architectures with a hardware register named SP,
the name prefix distinguishes references to the virtual stack pointer
from references to the architectural SP register.
That is, x-8(SP) and -8(SP) are different memory locations:
the first refers to the virtual stack pointer pseudo-register,
while the second refers to the hardware's SP register.
// 对SP和PC的访问都应该带上name,如果要访问对应的硬件寄存器,
// 可以用RSP
On machines where SP and PC are traditionally aliases for a physical,
numbered register, in the Go assembler the names SP and PC are still
treated specially; for instance, references to SP require a symbol,
much like FP. To access the actual hardware register use the true R name.
For example, on the ARM architecture the hardware
SP and PC are accessible as R13 and R15.

程序跳转和流控制是通过跳转PC的偏移量或者label实现的, label只对当前的function可见:

next:
MOVW $0, R1
JMP next

虚拟指令(Directives)

// 用虚拟指令来封装了text/data section
The assembler uses various directives to bind text and data to symbol names.

下面是一个真实的Go Plan9汇编中的function定义:

TEXT runtime·profileloop(SB),NOSPLIT,$8
MOVQ $runtime·profileloop1(SB), CX
MOVQ CX, 0(SP)
CALL runtime·externalthreadhandler(SB)
RET

// 定义参数通常需要指定size,如$24-8
the frame size is followed by an argument size, separated by a minus sign.
// 如果NOSPLIT没有指定,参数的size是必须指定的
If NOSPLIT is not specified for the TEXT, the argument size must be provided.
// Go汇编还可以声明调用.go声明的代码,但需要通过·来声明
// package·function的调用,这里的·可以通过Shift + Option + 9输入.

// Global指定后面跟着DATA指令可以定义全局标签,
// 没有赋值的label全部被清零.
Global data symbols are defined by a sequence of initializing DATA directives
followed by a GLOBL directive. Each DATA directive initializes a section of the
corresponding memory. The memory not explicitly initialized is zeroed.
The general form of the DATA directive is:

DATA symbol+offset(SB)/width, value

// 上面的语句初始化symbol+offset(SB)的数据中width bytes,赋值为value
which initializes the symbol memory at the given offset and width with the
// 相对于栈操作,SB的操作都是增地址,栈是减地址
given value. The DATA directives for a given symbol must be written with
increasing offsets.

例3: 一个简单的Go程序,通过go tool compile -S 获取Plan9反汇编结果:

$ GOOS=darwin GOARCH=amd64 go tool compile -S examples/e3/e3.go


"".main t=1 size=64 value=0 args=0x0 locals=0x8
0x0000 00000 (examples/e3/e3.go:3) TEXT "".main(SB), $8-0
0x0000 00000 (examples/e3/e3.go:3) MOVQ (TLS), CX
0x0009 00009 (examples/e3/e3.go:3) CMPQ SP, 16(CX)
0x000d 00013 (examples/e3/e3.go:3) JLS 52
0x000f 00015 (examples/e3/e3.go:3) SUBQ $8, SP

...

References

A Manual for the Plan 9 assembler

A Quick Guide to Go's Assembler

Things I learned writing a JIT in Go

Assembly

SIMD


总数:0 页次:1/0 首页 尾页  
总数:0 页次:1/0 首页 尾页  


所在合集/目录
golang 更多
汇编 更多



发表评论:
文本/html模式切换 插入图片 文本/html模式切换


附件:



NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.

Copyright © 2005-2020 clq, All Rights Reserved
版权所有
桂ICP备15002303号-1