Go plan9 汇编:手写汇编
原创文章,欢迎转载,转载请注明出处,谢谢。
0. 前言
在 Go plan9 汇编: 打通应用到底层的任督二脉 一文中介绍了从应用程序到汇编指令的转换。本文将结合汇编和 Go 程序实现手写基本的汇编指令,以加深对 Go plan9 汇编的了解。
1. 手写汇编
1.1 全局变量
首先写一个打印整型变量的函数如下:
// ex1/ex1.go
package main
var a = 9527
func main() {
print(a)
}
使用 go tool compile -S -N -l 输出程序的汇编代码:
# go tool compile -S -N -l ex0.go
main.main STEXT size=50 args=0x0 locals=0x10 funcid=0x0 align=0x0
...
main.a SNOPTRDATA size=8
0x0000 37 25 00 00 00 00 00 00 7%......
这里省略了 main.main 的汇编输出,重点关注 main.a 这个变量。输出的 main.a 表示汇编的标识符,SNOPTRDATA 表示这个变量是不包括指针的,这是给垃圾回收器看的,当扫描到这个变量时,垃圾回收器会跳过这个变量的回收。size=8 是这个变量的大小。重点在 0x0000 37 25 00 00 00 00 00 00,这段是 9527 在内存中的排列,0x2537 是 9527 的十六进制表示。
1.1.1 汇编实现全局变量
我们可以写汇编实现全局变量的输出。注意,本文不是汇编的教程,不会过多介绍 Go plan9 汇编的语法内容,关于这方面可以看曹大的 Go 语言高级编程:汇编语言(写的真是太好了!)。
首先,Go plan9 汇编是需要和 Go 文件一起协同工作的。这里
// ex1/ex1.go
package main
import (
"ex1/pkg"
)
func main() {
println(pkg.Id)
}
在 main 包中打印 pkg 包的 Id 变量。
// ex1/pkg/pkg.go
package pkg
var Id int
我们可以写汇编实现 Id 变量的定义,如下:
// ex1/pkg/pkg_amd64.s
#include "textflag.h"
GLOBL ·Id(SB),NOPTR,$8
DATA ·Id+0(SB)/1,$0x37
DATA ·Id+1(SB)/1,$0x25
DATA ·Id+2(SB)/1,$0x00
DATA ·Id+3(SB)/1,$0x00
DATA ·Id+4(SB)/1,$0x00
DATA ·Id+5(SB)/1,$0x00
DATA ·Id+6(SB)/1,$0x00
DATA ·Id+7(SB)/1,$0x00
NOPTR 表示变量 Id 不包括指针,$8 表示变量占 8 个字节。DATA 声明变量存储在内存中的 data 段,内存中的段如下。

运行上述程序:
# go run ex1.go
9527
输出变量 9527,其内存分布如下:

从变量内存分布可以看出,我们申请的 int(8 字节) 内存,只有 2 个字节是真正被用到的。其它字节都是 0。我们可以节省空间申请 Id 为 2 个字节如下:
// ex1/pkg/pkg.go
package pkg
var Id int16
// ex1/pkg/pkg_amd64.s
#include "textflag.h"
GLOBL ·Id(SB),NOPTR,$8
DATA ·Id+0(SB)/1,$0x37
DATA ·Id+1(SB)/1,$0x25
输出:
# go run ex1.go
9527
改写 pkg_amd64.s:
#include "textflag.h"
GLOBL ·Id(SB),NOPTR,$2
DATA ·Id+0(SB)/1,$0x37
DATA ·Id+1(SB)/1,$0x25
DATA ·Id+2(SB)/1,$0x20
输出:
# go run ex1.go
9527
在 0x2537 之上的 1 个字节 0x20 并不会被 CPU 寻址到,CPU 会根据变量声明从内存中读取 2 个字节的 Id 变量送入寄存器中处理。
1.2 字符串
结合 Go 和汇编打印字符串:
// ex2/main.go
package main
import (
"ex2/pkg"
"fmt"
)
func main() {
fmt.Println(pkg.Name)
}
// ex2/pkg/pkg.go
package pkg
var Name string
字符串 Name 的声明在 pkg 包中,使用汇编定义变量 Name:
// ex2/pkg/pkg_amd64.s
#include "textflag.h"
GLOBL string<>(SB),NOPTR,$16
DATA string<>+0(SB)/8,$"Hello Wo"
DATA string<>+8(SB)/8,$"rld!"
GLOBL ·Name(SB),NOPTR|RODATA,$16
DATA ·Name+0(SB)/8,$string<>(SB)
DATA ·Name+8(SB)/8,$12
这里字符串变量实际是一个 16 字节的包括长度和指针的结构体。变量定义在:
GLOBL ·Name(SB),NOPTR|RODATA,$16
DATA ·Name+0(SB)/8,$string<>(SB)
DATA ·Name+8(SB)/8,$12
前 8 个字节指向的是存储实际字符串的内存地址,后 8 个字节是字符串的长度。真实的字符串存储在内存中的数据段。这里 string<> 表示该变量 string 时不可导出变量,否则外部 Go 程序可直接访问字符串变量。
画出内存分布图如下:

2. 小结
我们顺着上述思路可以继续函数的汇编实现,不过本文重点是了解汇编的写法,不是真正去写汇编。我们通过两个简单的全局变量和字符串的汇编示例,了解汇编代码的写法。在实际应用中几乎不会自己去写,重在了解。更多关于汇编实现的内容可以参考曹大的 Go 高级编程。
Go plan9 汇编:手写汇编的更多相关文章
- Linux环境下使用dosemu写汇编
本章学习内容是汇编语言,现在直接写汇编的机会不多了,但一定要能读懂,信息安全的核心思维方式“逆向”在这有很好很直接的体现,反汇编就是直接的逆向工程. 所以我在前几天的学习中在Ubuntu环境下安装了可 ...
- 手写PE文件(二)
[文章标题]: 纯手工编写的PE可执行程序 [文章作者]: Kinney [作者邮箱]: mohen_ng@sina.cn [下载地址]: 自己搜索下载 [使用工具]: C32 [操作平台]: win ...
- 010Edit手写PE
前言PE结构DOS头IMAGE_DOS_HEADERPE头介绍总大小[248字节]结构体含义标记(4字节)0x4550文件头(20字节)扩展头(224字节)为程序添加ExitProcess函数 前言 ...
- JUC 并发编程--05, Volatile关键字特性: 可见性, 不保证原子性,禁止指令重排, 代码证明过程. CAS了解么 , ABA怎么解决, 手写自旋锁和死锁
问: 了解volatile关键字么? 答: 他是java 的关键字, 保证可见性, 不保证原子性, 禁止指令重排 问: 你说的这三个特性, 能写代码证明么? 答: .... 问: 听说过 CAS么 他 ...
- 【Win 10 应用开发】手写识别
记得前面(忘了是哪天写的,反正是前些天,请用力点击这里观看)老周讲了一个14393新增的控件,可以很轻松地结合InkCanvas来完成涂鸦.其实,InkCanvas除了涂鸦外,另一个大用途是墨迹识别, ...
- JS / Egret 单笔手写识别、手势识别
UnistrokeRecognizer 单笔手写识别.手势识别 UnistrokeRecognizer : https://github.com/RichLiu1023/UnistrokeRecogn ...
- 如何用卷积神经网络CNN识别手写数字集?
前几天用CNN识别手写数字集,后来看到kaggle上有一个比赛是识别手写数字集的,已经进行了一年多了,目前有1179个有效提交,最高的是100%,我做了一下,用keras做的,一开始用最简单的MLP, ...
- 【转】机器学习教程 十四-利用tensorflow做手写数字识别
模式识别领域应用机器学习的场景非常多,手写识别就是其中一种,最简单的数字识别是一个多类分类问题,我们借这个多类分类问题来介绍一下google最新开源的tensorflow框架,后面深度学习的内容都会基 ...
- caffe_手写数字识别Lenet模型理解
这两天看了Lenet的模型理解,很简单的手写数字CNN网络,90年代美国用它来识别钞票,准确率还是很高的,所以它也是一个很经典的模型.而且学习这个模型也有助于我们理解更大的网络比如Imagenet等等 ...
- 使用神经网络来识别手写数字【译】(三)- 用Python代码实现
实现我们分类数字的网络 好,让我们使用随机梯度下降和 MNIST训练数据来写一个程序来学习怎样识别手写数字. 我们用Python (2.7) 来实现.只有 74 行代码!我们需要的第一个东西是 MNI ...
随机推荐
- 不是人家太装逼,而是我们太low
在一个社团的迎新的时候,每个人自我介绍.等到一个一身LV,爱马仕的女孩子自我介绍,说起爱好,她想了想说:喜欢跑车.然后很淡定的坐下了.很多同学你看我我看你,投以"炫富"的判断目光- ...
- Qt 学习笔记 - 第四章 - Qt的三驾马车之 - 网络编程
Qt 学习笔记全系列传送门: Qt 学习笔记 - 第一章 - 快速开始.信号与槽 Qt 学习笔记 - 第二章 - 添加图片.布局.界面切换 Qt 学习笔记 - 第三章 - Qt的三驾马车之一 - 串口 ...
- yb课堂实战之轮播图接口引入本地缓存 《二十一》
轮播图接口引入缓存 CacheKeyManager.java package net.ybclass.online_ybclass.config; /** * 缓存key管理类 */ public c ...
- Curve 替换 Ceph 在网易云音乐的实践
Curve 块存储已在生产环境上线使用近三年,经受住了各种异常和极端场景的考验,性能和稳定性均超出核心业务需求预期 网易云音乐背景 网易云音乐是中国领先的在线音乐平台之一,为音乐爱好者提供互动的内容社 ...
- [oeasy]python0011_ 字符序号_ordinal_ord
序号(ordinal) 回忆上次内容 hello world 不是从来就有的 来自于unix和c 虽然我们今天有各种先进的学习手段 最早的高级语言学习是从最早的那张打字机用纸 ...
- oeasy教您玩转vim - 78 - # 操作系统文件格式 fileformat
文件系统换行格式 fileformat 回忆保留环境的细节 上次我们了解了viminfo 他能够保存 命令行历史 标记 寄存器 把他和 :mksession 一起使用就可以完美复原环境了 还有什么 ...
- java集合解析
1,java集合体系 2,Colletion集合 子接口有List和Set (1)List接口:ArrayList,Vector,LinkedList list是collection接口的子接口,特点 ...
- 单细胞测序最好的教程(十):细胞类型注释迁移|万能的Transformer
作者按 本章节主要讲解了基于transformer的迁移注释方法TOSICA,该算法在迁移注释上达到了SOTA的水平,在注释这么卷的赛道愣是杀出了一条血路.本教程首发于单细胞最好的中文教程,未经授权许 ...
- Microsoft Dynamics CRM 插件被限制2分钟超时解决方案
背景: 在隔离模式"沙箱"中运行的插件或自定义工作流活动将有2分钟的硬限制.如果你的插件很复杂,需要超过2分钟,有一些解决方法. CRM on premise (本地版) 选择插件 ...
- JAVA并发编程理论基础
注:本文章是对极客时间<java并发编程实战>学习归纳总结,更多知识点可到原文 java并发编程实战 进行学习.如果侵权,联系删除: 一.并发编程的BUG的源头 1.1 缓存导致的可见性问 ...