Go 语言汇编快速入门

2023-05-16

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

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

Go ASM ( 译者注:ASM 是汇编的简写 ) 是一种被 Go 编译器使用的特殊形式的汇编语言,而且它基于 Plan 9 输入风格,所以是一个不错的选择。

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

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

第一步

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

NASM x86NASM x64Go ASMeaxraxAXebxrbxBXecxrcxCX………

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

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

  • FP: 帧指针 –参数和局部变量–
  • PC: 程序计数器 –跳转和分支–
  • SB: 静态基址指针 –全局符号–
  • SP: 栈指针 –栈的顶端–.

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

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

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

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

IntelAT&TGomov eax, 1movl $1, %eaxMOVQ $1, AXmov rbx, 0ffhmovl $0xff, %rbxMOVQ $(0xff), BXmov ecx, [ebx+3]movl 3(%ebx), %ecxMOVQ 2(BX), CX

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

global start

section .bss
    …

section .data
    …

section .text
start:
    mov     rax, 0x2000001
    mov     rdi, 0x00
    syscall

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

DATA     myInt<>+0x00(SB)/8, $42
GLOBL     myInt<>(SB), RODATA, $8

// func foo()
TEXT ·foo(SB), NOSPLIT, $0
    MOVQ     $0, DX
    LEAQ     myInt<>(SB), DX
    RET

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

在 Go 中调用汇编代码

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

hello.go

package main

func neg(x uint64) int64

func main() {
    println(neg(42))
}

hello_amd64.s

TEXT ·neg(SB), NOSPLIT, $0
    MOVQ     x+0(FP), AX
    NEGQ     AX
    MOVQ     AX, ret+8(FP)
    RET

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

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

过程中的 TEXT ·neg(SB), NOSPLIT, $0 意味着:

  • TEXT: 这个符号位于 text section。
  • ·neg: 该过程的包符号和符号。
  • (SB): 词法分析器会用到。
  • NOSPLIT: 使得没有必要定义参数大小。–可以省略不写–
  • $0: 参数的大小, 如果定义了NOSPLIT 就是 $0 。

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

还有一份资源可以帮助学习 Go 文件的编译过程,我们可以看下 go tool build -S生成的 Go ASM 。

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

MacOS 中的系统调用

MacOS 中的系统调用需要在加上调用号 0x2000000 后才能被调用,举个例子,exit 系统调用就是 0x2000001 。调用号开始处的 2 是因为有多个种类的调用被定义在了手游拍卖重叠的调用号范围。

#define SYSCALL_CLASS_NONE    0    /* Invalid */
#define SYSCALL_CLASS_MACH    1    /* Mach */    
#define SYSCALL_CLASS_UNIX    2    /* Unix/BSD */
#define SYSCALL_CLASS_MDEP    3    /* Machine-dependent */
#define SYSCALL_CLASS_DIAG    4    /* Diagnostics */

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

NASM 中的写法类似这样:

mov     rax, 0x2000004     ; 写系统调用
mov     rdi, 1             ; 参数 1 fd (stdout)
mov     rsi, rcx         ; 参数 2 buf
mov     rdx, 16         ; 参数 3 count
syscall

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

MOVL     $1,  DI         // 参数 1 fd (stdout)
LEAQ     CX,  SI         // 参数 2 buf
MOVL     $16, DX         // 参数 3 count
MOVL     $(0x2000000+4), AX     // 写系统调用
SYSCALL

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

使用字符串

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

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

section data:
foo: db "My random string", 0x00

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

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

DATA  foo<>+0x00(SB)/8, $"My rando"
DATA  foo<>+0x08(SB)/8, $"m string"
DATA  foo<>+0x16(SB)/1, $0x0a
GLOBL foo<>(SB), RODATA, $24

TEXT ·helloWorld(SB), NOSPLIT, $0
    MOVL     $(0x2000000+4), AX     // syscall write
    MOVQ     $1, DI             // arg 1 fd
    LEAQ     foo<>(SB), SI         // arg 2 buf
    MOVL     $24, DX         // arg 3 count
    SYSCALL
    RET

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

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

在安全领域使用?

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Go 语言汇编快速入门 的相关文章

  • 加速matlab运行

    一 遵守Performance Acceleration的规则 二 遵守三条规则 一 遵守Performance Acceleration的规则 关于什么是 Performance Acceleration 请参阅matlab的帮助文件 我
  • 上海~还是伤心了啊

    还有西安
  • Zabbix 数据库表结构说明

    该文档提供了zabbix中mysql数据库中各个表及其中字段的详细解释 acknowledges表 xff08 空 xff09 当trigger发生状态变化后 xff0c 即产生某个事件 xff08 event xff09 后 xff0c
  • 2020CVPR对抗样本相关论文整理(有开源代码)

    目录 攻击防御 攻击 1 Towards Large yet Imperceptible Adversarial Image Perturbations withPerceptual Color Distance code链接 朝向具有感知
  • GAN & 对抗样本

    目录 关于对抗样本的解释GAN原理简介GAN生成对抗样本的发展 关于对抗样本的解释 对于对抗样本为何能够攻击成功 xff0c 目前有以下三种解释 xff1a 高维空间的线性模型解释 xff1a 当输入为图像时 xff0c 沿着梯度方向很小的
  • 块元素与内联元素的区别

    在css盒子模型中 xff0c 我们提到了html元素中的块元素 xff08 block element xff09 和内联元素 xff08 inline element xff09 那么它们究竟是什么呢 xff1f 其实 xff0c 这两
  • Ubuntu实用安装

    1 用DVD xff0f 服务器版 ubuntu 来安装命令行系统 2 编辑更新软件源 sudo cp etc apt source list etc apt source list bak 3 安装 X 窗口系统 xff1a sudo a
  • 关于Haar名称一点想说的:Haar而非Harr

    见到一些中文文献 博客 师兄们的简历都出现以一个叫 Harr 的特征 xff0c 有些疑惑 刨根问底一下 xff0c 最后得出结论Harr应该是对Haar的误写 Haar特征因为使用的是Haar小波变换而得名 xff0c 哈尔小波转换 是于
  • 安装远程连接Ubuntu Server 的图形界面——x2go远程连接桌面

    想要远程连接你的Ubuntu服务器的图形界面么 xff1f 这里有个简单的指导告诉你如何使用X2Go来实现 xff0c 这是一个NX远程桌面协议的衍生版本 你所需要做的就是 1 在服务器上面安装X2Go服务端和桌面环境 xff0c 2 在客
  • PHP正则表达式之\A、\Z、 \z、^、$

    文章目录 A Z z 断言与 之间的区别单行模式和多行模式的差异换行符匹配的差异 示例代码及解读文中提到的模式修饰符D PCRE DOLLAR ENDONLY m PCRE MULTILINE A Z z 断言与 之间的区别 A xff0c
  • #发布npm包遇到错误,因为用了淘宝镜像地址的原因的解决方法-403 403 Forbidden - PUT https://registry.npmmirror.com/-/user/org.cou

    使用npm login 也可以使用npm adduser 登录准备发布npm依赖包到npm时 xff0c 遇到问题 xff1a span class token function npm span ERR span class token
  • 面向对象设计和结构化分析设计(软件设计师备考笔记)

    目录 第十章 面向对象设计和结构化分析设计 第一节 结构化设计 第二节 UML 第三节 面向对象设计 设计原则 第四节 面向对象设计 设计模式 第五节 结构化分析 数据流图 DFD 必考 下午第一道题 第六节 面向对象设计方法 多态与绑定
  • 大厂Mysql高频面试题!java操作excelpoi

    微服务的发展 微服务倡导将复杂的单体应用拆分为若干个功能简单 松耦合的服务 xff0c 这样可以降低开发难度 增强扩展性 便于敏捷开发 当前被越来越多的开发者推崇 xff0c 很多互联网行业巨头 开源社区等都开始了微服务的讨论和实践 微服务
  • 知已知彼 ^.^

    如何做一个让男人尊敬的精致女人 转贴 作者 LUKECYK 浏览 160 1 如果一个男人开始怠慢你 xff0c 请你离开他 不懂得疼惜你的男人不要为之不舍 xff0c 更不必继续付出你的柔情和爱情 2 任何时候 xff0c 不要为一个负心
  • 单片机 -定时器计数器工作原理及工作方式

    时钟周期 时钟周期 T 是时序中最小的时间单位 xff0c 具体计算的方法就是 1 时钟源频率 xff0c 假如单片的晶振是 11 0592M xff0c 那么对于我们这个单片机系统来说 xff0c 时钟周期 61 1 11059200 秒
  • 单片机 LCD1602

    LCD1602为工业字符型液晶 xff0c LCD表示LiquidCrystal Display 能够同时显示16 x 2 xff08 16列2行 xff09 即32个字符 1602液晶也叫1602字符型液晶 xff0c 它是一种专门用来显
  • javascript进制及进制之间的转换

    计算机中常用的进制数有二进制 八进制 十进制 十六进制 一 十进制 转 其他 span class token keyword var span x span class token operator 61 span span class
  • 解决进入Ubuntu系统花屏的问题

    安装ubuntu后进入系统花屏 详细步骤 详细步骤 开机选择进入Ubuntu的高级系统模式 gt 恢复模式 xff0c 选择root xff0c 进入命令行界面 输入 xff1a sudo vim etc default grub 打开gr
  • 李沐:用随机梯度下降来优化人生

    用SGD来优化人生 要有目标目标要大坚持走痛苦的卷可以躺平四处看看快也是慢赢在起点很远也能到达独一无二简单最好 转载 xff0c 用随机梯度下降来优化人生1 xff1a https zhuanlan zhihu com p 41400931

随机推荐

  • Ubuntu18.04 + kinova joca2机械臂 + RealSense D435i深度相机进行eye to hand手眼标定

    文章目录 前言一 前期准备1 RealSense D435i安装2 Kinova ROS安装 二 手眼标定环境配置1 visip2 aruco ros3 easy handeye 三 标定前准备1 终端python版本设置2 opencv4
  • 相机成像原理详解

    ybwu 64 whu edu cn 被摄景物反射出的光线通过照相镜头 xff08 摄景物镜 xff09 和控制曝光量的快门聚焦后 xff0c 被摄景物在暗箱内的感光材料上形成潜像 xff0c 经冲洗处理 xff08 即显影 定影 xff0
  • python和numpy matplotlib版本匹配,以及安装指定版本库

    python和numpy matplotlib版本匹配 xff0c 以及安装指定版本库 文章目录 python和numpy matplotlib版本匹配 xff0c 以及安装指定版本库一 卸载二 安装三 验证 Matplotlib is a
  • wegame桌面丢失(所有软件都可用)

    1 打开此电脑 2 右上角搜索引擎里输入代码tgp daemon 即可 如果想要放在左面或者添加快捷方式邮寄此软件 会出现 创建快捷方式 或者固定到 开始位置
  • 人脸识别的LOSS(多分类Softamx)

    人脸1 xff1a N应用 xff1a https blog csdn net intflojx article details 81278330 超多分类的Softmax 早期深度人脸识别方法 xff0c 框架为CNN 43 Softma
  • 一些范冰冰的照片

    你可以说她YD xff0c 也可以说她XJ xff0c 但是你不能否认她的美丽 偶就是无敌小超人 xff0c 克塞前来拜访 热门圈子 xff1a 王仁甫 张佑赫 王绍伟 tony 明道 快速评论 共 19 条回复
  • vnc的默认端口修改

    http inthirties com 90 thread 1261 1 1 html vnc的默认端口是5901 xff0c 这个说法是不对的 vnc并不是只有一个端口 以前另一个文章介绍了nvcserver的配置用户的过程 xff0c
  • JavaScript 关于进制之间的转换实现

    JS要实现进制之间的转换 xff0c 可以利用parseInt xff0c toString完成 1 n进制 gt 10进制 xff1a parseInt string radix 2 n进制 gt radix进制 xff1a a toSt
  • VNC Server配置

    VNC登录用户缺省是root xff0c 但在安装oracle时必须用oracle用户的身份登录 xff0c 下面我们就以oracle为例说明如何配置VNC xff0c 从而可以使用不同的用户登录到主机 步骤描述如下 xff1a 步骤一 x
  • 文字检测识别技术的未来发展趋势和面临的选择

    未来发展趋势和面临的挑战 1文本检测与识别技术的未来发展趋势 场景文本检测与识别的研究发展趋势 场景文本检测识别目前来讲大概分为场景文本检测 场景文本识别 以及端到端文本检测和识别三个主要的方向 其中文本检测方法主要是包括基于文本框回归的分
  • [SIGCOMM2016]Robotron: Top-down Network Management at Facebook Scale

    Facebook面临的问题 分布式配置 xff1a 有很多配置需要在不同的系统中更改 多个Domain xff1a Facebook需要管理网络的网络版本控制 xff1a 需要管理不同版本的网络同时运行 依赖 xff1a 将新路由器添加到
  • Adversary Attack(对抗攻击)论文阅读笔记

    引言 最近开始学习Adversary Attack 对抗攻击 有关的内容 xff0c 于是便从Ian GoodFollow的论文开始读起 xff0c 后面每篇博客都会列举三篇的阅读笔记 xff0c 来记录学习的经历 如果有讲得不到位或者您有
  • 海睿思分享 | 浅谈数仓指标体系管理

    什么是指标 xff1f 指标 xff0c 是用于衡量事物发展程度的单位或方法 xff0c 也常被称作度量 xff0c 通常情况下也是报表统计的字段 xff0c 例如 xff1a 人口数 营业收入 用户数 利润率 成功率 失败率 覆盖率等 1
  • PyTorch 实战:计算 Wasserstein 距离

    xff08 给 Python开发者 加星标 xff0c 提升Python技能 xff09 编译 xff1a 机器之心 xff0c 作者 xff1a Daniel Daza 最优传输理论及 Wasserstein 距离是很多读者都希望了解的基
  • Java8 Lambda表达式教程

    1 什么是 表达式 表达式本质上是一个匿名方法 让我们来看下面这个例子 xff1a public int add int x int y return x 43 y 转成 表达式后是这个样子 xff1a int x int y gt x 4
  • VNC连接失败:The connection was refused by the host computer

    解决方法 xff1a 1 用Xshell登陆自己的服务器 2 在命令行中输入vncserver 命令行中出现 xff1a Warning optimal6 2 is taken because of tmp X2 lock Remove t
  • ACM会用到的一点数学知识

    1 费马小定理 xff1a a p mod p 61 a p为素数 xff0c 且a不是p的倍数 2 数n的约数个数 xff1a n分解因数为p1 s1 p2 s2 pm sm 则约数个数为 s1 43 1 s2 43 1 sm 43 1
  • SVN的Status总结

    执行SVN up和svn merge等命令出现在首位置的各字母含义如下 xff1a 无修改 A 新增 C 冲突 D 删除 G 合并 I 忽略 M 改变 R 替换 X 未纳入版本控制 xff0c 但被外部定义所用 未纳入版本控制 该项目已遗失
  • linux 下中文编码转换问题

    目标 xff1a 接收网络传过来的字节序 xff0c 转换字符串 全英文的情况下直接保存string即可 xff0c 带中文的情况试了好久故做如下记录 1 首先确认gcc 应该是utf 8的格式来存储字符串的 通过cmake 加入 fexe
  • Go 语言汇编快速入门

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