Go 语言汇编快速入门

在 的源码中包含大量汇编语句,最优秀的示例代码位于 , 和 这些库中,但是从这里入门的话实在太过于痛苦,这些示例都是着力于系统操作和性能的运行代码。

对于没有经验的 语言爱好者来说,这样会使通过库代码的学习过程遇到很大困难 。这也是撰写本文的原因所在。

( 译者注: 是汇编的简写 ) 是一种被 编译器使用的特殊形式的汇编语言,而且它基于 (译者注:来自贝尔实验室的概念网络操作系统 )输入风格,所以先从 文档 开始是一个不错的选择。

注意:本文的内容是基于 架构,但大多数示例也能兼容 架构。

一些例子是从原始文档中选取出来的,主要目的是建立一个综合的统一标准摘要,涵盖那些最重要/有用的主题。

第一步

和标准的汇编语法( 或 )不太一样,首先你会发现它是架构独立的,没有所谓的 或 位寄存器,如下图所示:

大部分寄存器符号都依赖于架构。

另外, 还有四个预定义的符号作为伪寄存器。它们不是真正意义上的寄存器,而是被工具链维持出来的虚拟寄存器,这些符号在所有架构上都完全一样:

: 帧指针 –参数和局部变量–

: 程序计数器 –跳转和分支–

: 静态基址指针 –全局符号–

: 栈指针 –栈的顶端–.

这些虚拟寄存器在 中占有了重要地位,并且被广泛使用,其中最重要的就要属 和 了。

伪寄存器 可以看作是内存的起始地址,所以 就是 在内存中的地址。语法中有两种修饰符, 和 (是一个整数)。第一种情况 代表了一个私有元素,只有在同一个源文件中才可以访问,类似于 里面的小写命名。第二种属于对相对地址加上一个偏移量后得到的地址,所以 就指向 之后 个字节处的地址。

伪寄存器 是一个虚拟帧指针,被用来引用过程参数,这些引用由编译器负责维护,它们将指向从伪寄存器处偏移的栈中参数。在一台 位机器上, 是第一个参数, 就是第二个参数。为了引用这些参数,编译器会强制它们的命名使用,这是出于清晰和可读性的考虑。所以 , 会把虚拟的 寄存器中的第一个参数放入到物理上的 寄存器,以及 , 会把第二个参数放入到 寄存器中。

读者可能已经注意到这种 语法类似 风格,但不完全一致:

另一处显著的差异就是全局源码文件结构, 中的代码结构是用 清晰的定义出来:

而在 汇编中则是靠预定义的 类型符号:

这种语法使得我们能够尽可能的在最适合的地方定义符号。

在 Go 中调用汇编代码

可以从介绍中发现, 中的汇编代码主要用于优化和与底层系统交互,这使得 并不会像其它的经典汇编代码那样独立运行。 必须在 代码中调用。

hello.go

运行这份代码将会在终端打印出 。

注意子过程符号开始处的 中间点 · ,这是为了包名分隔,没有前缀的 等价于 。

过程中的 , , 意味着:

TEXT: 这个符号位于 text section。

·neg: 该过程的包符号和符号。

(SB): 词法分析器会用到。

NOSPLIT: 使得没有必要定义参数大小。–可以省略不写–

0 。

的步骤仍旧和往常一样,使用 命令, 编译器会根据文件名自动链接 文件。

还有一份资源可以帮助学习 文件的编译过程,我们可以看下 生成的 。

一些类似 和 的符号都是在 头文件中定义,因此用 包含 该文件可以有利于完成一次没有报错的完美编译。

MacOS 中的系统调用

中的系统调用需要在加上调用号 后才能被调用,举个例子, 系统调用就是 。调用号开始处的 是因为有多个种类的调用被定义在了重叠的调用号范围,这些类型都是定义在 这里 :

所有的 系统调用号列表可以在 这里 找到.

参数是通过这些寄存器 , , , , 和 传递给系统调用, 系统调用代码存放在 中。

中的写法类似这样:

与之相反, 中类似的例子则是像这样:

同样,系统调用代码被放置在 指令之前,这仅仅是通用写法,你可以像在 中那样直接把写系统调用放在最前面,编译后不会报任何错误。

使用字符串

现在我相信你已经能够写一些基本的汇编代码并运行了,例如经典的 。我们知道如何把一个参数传递给子过程,如何返回值和如果在数据 里面定义符号。你试过定义一个字符串么?

几天前我在编写一些汇编代码的时候遇到了这个问题,而我最关心的问题是,我该如何做才能去定义一个操蛋的字符串?嗯, 中可以像这样来定义字符串:

可这在 中不行,在我深入研究了我能从网上找到的所有 项目后,我还是没能找到一个定义简单字符串的示例。最后我在 汇编语言文档中找到了一个例子,它可以说明怎样让目标实现。

和 唯一的不同之处是使用双引号而非单引号,并且添加了一个 符号:

注意,定义字符串时不能放在一起,需要把它们定义在 字节( 位)的块中。

现在你可以深入 世界中写下你自己的超级快速和极端优化的代码,并请记住,去读那些操蛋的手册(微笑脸)。

在安全领域使用?

使用汇编除了优化你的 代码外,也可以很方便的避免触发常见签名从而规避防病毒软件,以及使用一些反编译技术规避沙箱来搜寻异常行为,或者只是让分析师哀嚎。

如果你对此有兴趣,我会在该主题的下一篇文章中介绍,敬请关注!

附录

https://golang.org/doc/asm

https://9p.io/sys/doc/asm.pdf

https://goroutines.com/asm

https://blog.sgmansfield.com/2017/04/a-foray-into-go-assembly-programming/

via: https://blog.hackercat.ninja/post/quick_intro_to_go_assembly/

作者:hcn

译者:sunzhaohao

校对:polaris1119

本文由 GCTT 原创编译,Go语言中文网 荣誉推出

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181119B0HRE100?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券