目录 Table of Contents
第一个汇编程序
Linux 汇编命令
Linux 下将汇编代码转换为可执行程序 :
as -o my-object-file.o helloworld.s
as
就是 assembler 这个命令, helloworld.s 是我们写的源代码文件, 然后转换为 my-object-file.o 这个 object 文件
-gstabs
参数产生带调试信息的 object 文件
64 环境下生成 32 位, 需要添加 --32
参数
ld my-object-file.o
ld
就是 link, 把我们的 .o 文件链接为可执行程序
你可以把多个 .o 文件链接起来
64 下生成 32 位程序需要添加 -m elf_i386
参数
如果你在某些 linux 版本下发现一些错误, 比如 ubuntu 之类的, 而且发现什么东西也没有找到, 建议看一下是不是这个没有安装 : sudo apt-get install g++-multilib
Hello world 示例
.data # 首先第一个声明 `.data`, 因为我 hello world 要把字符串打印出来, 字符串属于数据, 自然放到数据段里面.
msg:
.ascii "Hello world\n" # msg 表示我 hello world 这段数据所存放的起始地址, 它是一个标签
len = .-msg # 点 . 表示当前地址, 这个点减去 hello world 起始地址, 就是字符串的长度了, 然后把长度赋值到 len 里面
.text # 我们代码段从这里开始
.globl _start # 汇编程序的入口是 _start, 相当于 C 语言的 main 函数
_start:
movl $len, %edx
movl $msg, %ecx
movl $1, %ebx # 系统输出 (write 系统调用)
movl $4, %eax
int $0x80
movl $0, %ebx # 程序退出
movl $1, %eax
int $0x80
这个程序比较简单, 我把 hello world 打出来就行了.
那么 hello world 怎么打呢, 我就采用一种系统输出的方式, 这个系统调用.
我们写程序的时候, 最终你要是跟一些硬件资源相关的, 比如在屏幕上做什么输入输出, 读取文件, 进行某些内存分类与释放之类的操作, 这个实际上是操作系统给你提供功能的, 那么这些功能叫作系统调用
这种情况下, 我们要在屏幕上面, 或者说是命令行上面做一个 hello world 的输出, 也要通过操作系统提供给你的一个接口才能完成, 这个接口就是系统调用. 这里我们用的是叫作 write
的系统调用. 这个系统调用的功能是, 在你指定的一些文件上面输出你要的字符串或者数据.
系统调用
中断指令
系统调用是通过一条 x86 的中断指令 int $0x80
来实现的.
- 中断指令与系统调用
在执行这条中断指令的时候, 寄存器 eax 中存放的是系统调用的功能号, 而传给系统调用的参数则必须按照顺序放到寄存器 ebx, ecx, edx, esi, edi 中.
当系统调用完成之后, 返回值可以在寄存器 eax 中获得.
系统调用和一般的过程调用 (函数调用) 不一样. 系统调用是系统在帮你做事, 这个过程中程序的运行状态发生了大的改变# 而过程调用则是在程序自己内部空间里面调来调去.
- 参数个数问题
当一个系统调用所需的寄存器个数大于 5 的时候, 还是把系统调用的功能号保存在 eax 中, 然后全部的参数依次存放在一块连续的内存空间里面, 同时在 ebx 中保存指向该内存区域的指针.
返回值还是放在 eax 中.
程序解析
我们回过头看刚才的程序
movl $len, %edx # 告诉系统我要写入多少个数据, 用 byte 为单位
movl $msg, %ecx # 告诉系统我要写的这个数据, 起始地址在什么地方
movl $1, %ebx # 告诉系统调用, 我要把它写到 1 号输出, 1 号输出就是标准输出
movl $4, %eax # 系统调用号
int $0x80
movl $0, %ebx # 传递的参数为 0
movl $1, %eax # 系统调用号, 1 号就是程序退出
int $0x80
部分系统调用列表
比如 exit, ebx 里面是你输入的参数
fork 不说了, 就是产生一个子进程
read 我们后面会用, 从某个文件或者设备里面读取数据. 标号为 3# 文件描述符放到 ebx 里面, 比如 0 1 就是标准输入输出了, 还有 2 是标准错误输出, 从 3 号开始才是正常的文件描述符# ecx 刚才提到过, 就是你要读的地址放到 ecx 里面去# edx 来只是最多能读多少个数据# 返回值放到 eax 里面去, 一般来说读了多少个数据或者出错放到 eax 里面去
再往下是 close, 关闭一个文件
waitpid 就是等待某个我们的进程退出
然后 create 就是创建文件
unlink 实际上就是 delete, 把一个文件删除掉
然后就是执行某个程序以及改变当前的工作目录
更多关于 x86-32 linux 系统调用的参考资料 : x86-32 linux 系统调用的参考资料