介绍
汇编语言程序由定义好的段构成, 每个段都有不同的目的, 最常用的三个段如下
- 数据段: 声明带有初始值得数据
- bss 段: 声明使用 0 值初始化的数据元素
- 文本段: 声明指令代码的地方, 其他段可能没有, 但文本段是必须的
定义段
.section
命令语句可声明段, .section
语句只有一个参数, 这个参数用来声明段的类型.
实例
获取 cupid 的程序: demo.s
.section .data
output:
.ascii "The processor Vender ID is 'xxxxxxxxxxxx'\n"
.section .text
.globl _start
_start:
// 获取 CPU ID
movl $0, %eax
cpuid
// 将 CPU ID 填充到 output 的占位符部分
movl $output, %edi
movl %ebx, 28(%edi)
movl %edx, 32(%edi)
movl %ecx, 36(%edi)
// 系统调用, 显示 CPUID
movl $4, %eax
movl $1, %ebx
movl $output, %ecx
movl $42, %edx
int $0x80
movl $1, %eax
movl $0, %ebx
int $0x80
// 系统调用, 返回程序执行结果
movl $1, %eax
movl $0, %ebx
int $0x80
ret
上面程序程序声明了一个
数据段
和文本段
, 在数据段中使用 .ascii 声明了一个预定义的字符串, 其起始内存地址由标签output
指示, 后面的 x 作为占位符以放置读到的cpuid.
.globl
命令用来声明外部程序可以访问的程序标签,_start
标签定义程序执行起始内存地址, 因为 ld 程序默认在链接时会去寻找_start
, 不过也可以通过-e
参数更改默认的起始地址标签.
int $0x80
将生成具有 0x80 的软件中断, Linux 可利用该中断来进行系统函数调用, Linux 的 write 系统调用用于把字节写入文件, 其参数如下
- EAX 包含系统调用值
- EBX 包含要写入的文件描述符
- ECX 包含字符串的开头
- EDX 包含字符串的长度
Linux 一切皆文件, 因此
movl $1, %ebx
告诉系统调用 wirte 将信息输出到标准输出 STDOUT, 即控制台显示屏上.通过系统调用 1 (退出函数), 程序被正确终止, 并返回到命令提示符, EBX 寄存器包含程序返回给 shell 的退出代码.
编译运行
-
使用 as 进行编译:
$ as demo.s -32
上面是 32 位程序, 如果是 64 位的电脑, 需要使用
-32
指定编译生成的是32位的程序. -
使用 ld 进行链接:
$ ld ./a.out -o demo -m elf_i386
同样 64 位的电脑链接 32 位程序需要使用 -m elf_i386 指示生成的可执行程序是 32 位类型的.
-
运行
$ ./demo The processor Vender ID is 'GenuineIntel'
使用 gcc 直接编译
gcc 标签识别 main
标签, 更改 _start
为 main
然后执行:
$ gcc demo.s -m32
$ ./a.out
The processor Vender ID is 'GenuineIntel'
使用 WSL
如果使用的是 WSL, 64位的 WSL 环境默认无法编译运行32位程序, 可通过如下方案运行 (参考https://github.com/Microsoft/WSL/issues/2468):
- 安装 qemu and binfmt
并设置每次重启 WSL 都激活该功能sudo apt update sudo apt install qemu-user-static sudo update-binfmts --install i386 /usr/bin/qemu-i386-static --magic '\x7fELF\x01\x01\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x03\x00\x01\x00\x00\x00' --mask '\xff\xff\xff\xff\xff\xff\xff\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xf8\xff\xff\xff\xff\xff\xff\xff'
sudo service binfmt-support start
- 接下来启用 i386 体系结构和 package
sudo dpkg --add-architecture i386 sudo apt update sudo apt install cpp-9:i386 sudo apt install gcc:i386
- 设置开机启动
vim /etc/myinit.sh sudo service binfmt-support start
网友评论