在Linux下的汇编为AT&T格式。
1 目前学习汇编的步骤
- 怎么将汇编代码添加到汇编程序框架中。
- 理解汇编语句的含义。
- 汇编源代码是怎么转换为可执行代码的。
2 AT&T汇编程序结构
在汇编中,一般具有如下的结构:
- 数据段(.data)
- 附加段(.bss)
- 代码段(.text)
在汇编程序中,数据和附加段可选,但在汇编程序中经常包含有这两个段。代码段必含,是声明指令代码的地方。
(1)定义段
每个段用”.section”或“.标识符”标识。如”.section.data”或”.data”就形象的表示一个数据段。其实对于对于系统来说,它只是一个段,以“.”标识。
(2) 汇编程序入口
当汇编代码被编译成为可执行程序的时候,连接器必须要知道程序入口点在哪里。在GNU汇编器中,_start被定义为汇编程序的入口标识符,_start标识符暗示程序从这里开始运行。
为了让这个入口标识符能被其它文件的汇编代码认识,提供 “.globl”指令实现,即用.globl _start语句声明程序入口标识符。
所以,一个AT&T汇编程序的结构大概如此:
.section .data < initialized data here>
.section .bss < uninitialized data here>
.section .text .globl _start _start: <instruction code goes here> |
在代码段中,汇编代码依靠系统调用来完成一些操作,包括在程序退出之前的一些操作及程序退出操作。
3一个简单的汇编程序
(1) 数据段
.data msg: .ascii "write asm code first day\n" len= .-msg |
- 形象的标名数据段。
- .ascii为AT&T汇编中的数据类型,类似的数据类型还有“.short”、“.int”、“.long”、“.byte”、“.float”、“.double”、“.comm”。第二条语句叫表示msg作为后续字符串的起始地址。
- len求得字符串的长度。
(2) 代码段
代码段主要是用系统调用来完成程序功能。包含“程序入口”、“功能代码”和“程序退出代码”。
[1]程序入口
.text .global _start _start: |
按照GNU AT&T汇编的格式,_start为汇编程序的入口,且由.global保证其它文件内的汇编代码可识别_start入口。
[2]功能代码
_start: movl $4, %eax #Linux system wirte call movl$1, %ebx #STDOUT movl $msg, %ecx #Give string start address to %ecx movl $len, %edx #Give string lenght to %edx int $0x80 #Software interrupt |
这几行代码表示一次Linux系统调用。Linux系统的软件中断由命令int发起。系统调用的中断号为0x80处。int $0x80引来一次系统调用软件中断,在一次Linux系统调用中会访问一些内核函数。在这次系统调用中断过程中将执行什么样的系统调用取决于eax寄存器内的值。每一种系统调用对应一个内核函数的调用。
在int $0x80引发的系统调用中,在eax寄存器内不同的值表示不同的系统调用。4代表linux write system call,1代表linux
exitsystem call。And so on。
在linux 写系统调用(eax值为4)下,其它的寄存器内所存值也会代表一些含义:
- ebx包含要写向的文件描述符(STANDOUT:1,STDIN:0,STDERR:2)。
- ecx包含子符串的起始地址。
- edx包含ecx字符串的长度。
故而,在为写操作准备好所有的条件之后。int $0x80经执行引起的软件中断后,照eax内存的值就访问linux内核的一些函数,向控制台(ebx:1)输出字符串(ecx:msg)。
[3]程序退出
movl $1, %eax #Linux systemexit call movl $0, %ebx #Acceptprogram exit value int $0x80 #software interrupt |
Linux汇编程序的退出也是依靠系统调用来完成。此时寄存器eax中的值应该为1,ebx只是为了获得程序退出后返回给shell的值。
到此,一个简单的linux程序就编写好了,基本模糊的原理也给笔记清楚了。
4 编译执行AT&T linux汇编
加入以上各部分组成的代码文件名为,learn.s,则编译执行过程为:
as -o learn.o learn.s [生成learn.o文件]
ld -o learn learn.o [生成learn可执行文件]
./learn 得程序执行结果]
write asm code first day
5 总结
关于涉及到的AT&T汇编的语法:
- 立即数前面需要加$。
- 直接引用符号常数,在符号常数前加$表示引用符号常数的地址。
- movl %eax, %ebx,源操作数为eax内的值,目的操作数为ebx的值。源、目的操作数符合从左到右的操作顺序。
- 寄存器前面要加%。
- Linux 下用vim编辑器编辑AT&T代码时#表示注释符号。
初学汇编,在了解汇编程序框架后,如果不知代码段应该写什么内容,不明白要用哪一个寄存器来操作时。应该查查各寄存器在系统调用软件中断发生时(int $0x80)要发生的操作所对应的寄存器的值。这样,起码就能编写“hello world!”的入门代码了。
当然,要了解整个汇编代码的机制还得多编写,达到只需查询就可完成功能的目标。目前根据这个程序得到的经验是:汇编代码可以依靠系统调用软件中断来调用内核的函数,系统调用的类型由eax寄存器你的值。我们需要提前配置好eax及相关寄存器的值,从而实现咱的目标功能。一般是eax寄存器里面的值决定软件中断后linux系统调用的类型(eax:4linux write
system call,eax:1 linux exit system call),然后其它的寄存器配合这种统调用。[好像总结得有点浅显]
此次笔记记录完毕。