参考链接: 《Linux C编程一站式学习》
.section .data
data_items:
.long 3,67,34,222,45,75,54,34,44,33,22,11,66,0
.section .text
.globl _start
_start:
movl $0, %edi # move 0 into the index register
movl data_items(,%edi,4), %eax # load the first byte of data
movl %eax, %ebx # since this is the first item, %eax is
# the biggest
start_loop: # start loop
cmpl $0, %eax # check to see if we've hit the end
je loop_exit
incl %edi # load next value
movl data_items(,%edi,4), %eax
cmpl %ebx, %eax # compare values ebx is the biigest num , jle start_loop # jump to loop beginning if the new one isn't bigger: jle means if eax is less than or equals ebx
movl %eax, %ebx # move the value as the largest
jmp start_loop # jump to loop beginning
loop_exit:
# %ebx is the status code for the _exit system call
# and it already has the maximum number
movl $1, %eax #1 is the _exit() syscall
int $0x80
这是寒假表哥发到群里的一个asm文件,当时的要求有两个,一是得出输出结果,二是把这个文件想办法运行起来。当时由于胃痛提前睡觉,之后也把这个东西给忘了。现在补充学习一下。
首先显而易见这是个汇编语言的源程序文件。
但是语法和平常Windows下所见的汇编语言有所区别。因为
Windows使用intel语法,而UNIX平台的汇编器一直使用AT&T语法。
我们在linux环境下将其编译、链接并运行。
$ as test.s -o test.o #编译
$ ld test.o -o test #链接
$ ./test #运行
$ echo $? #打印结果
as是汇编语言的编译指令,生成test.o 即obj格式的目标文件
ld是链接程序,链接后生成可执行的exe
链接主要有两个作用,一是修改目标文件中的信息,对地址做重定位,二是把多个目标文件合并成一个可执行文件
运行结果是:
222
显然是求这组数的最大值的一个逻辑功能。 接下来再仔细看内容。
.section .data
data_items:
.long 3,67,34,222,45,75,54,34,44,33,22,11,66,0
.data数据段
.long指示声明一组数,每个数占32位,相当于C语言中的数组。这个数组开头定义了一个符号data_items,汇编器会把数组的首地址作为data_items符号所代表的地址,data_items类似于C语言中的数组名。data_items这个标号没有用.globl声明,因为它只在这个汇编程序内部使用,链接器不需要用到这个名字。
.section .text
.globl _start
_start:
.text开始代码段 这里注意下global和start的意义。
.globl指示告诉汇编器,_start这个符号要被链接器用到,所以要在目标文件的符号表中标记它是一个全局符号。
_start就像C程序的main函数一样特殊,是整个程序的入口,链接器在链接时会查找目标文件中的_start符号代表的地址,把它设置为整个程序的入口地址,所以每个汇编程序都要提供一个_start符号并且用.globl声明。
movl $0, %edi
movl data_items(,%edi,4), %eax
movl %eax, %ebx
初始化edi,指向数组的第0个元素。
然后把数组的第0个元素传送到eax寄存器中。4表示数组的每个元素占4字节,那么数组中第edi个元素的地址应该是data_items + edi * 4,写在指令中就是data_items(,%edi,4) ebx的初始值也是数组的第0个元素。
start_loop:
cmpl $0, %eax
je loop_exit
接下来进入循环,每次比较eax和0,eax表示当前的数,因为数组的最后一个数是0,所以比较到最后一个数的时候会跳出循环。
incl %edi
movl data_items(,%edi,4), %eax
edi的值加1,把数组的下一个数传到eax寄存器里
cmpl %ebx, %eax
jle start_loop
把当前数和截至目前的最大值ebx比较,如果最大值没有变,则跳到循环开头继续比较下一个数字。否则继续执行下一条指令。
movl %eax, %ebx
jmp start_loop
更新最大值,把eax的值传给ebx,然后再跳到开头比较下一个数。
loop_exit:
movl $1, %eax
int $0x80
loop_exit后面的指令调_exit系统调用退出程序。
_exit 的系统调用号为1 ,而32位系统eax寄存器保存系统调用号。
在Linux 的汇编语言中(AT&T,x86汇编两种语法的一种),int 指令被称为==软中断指令== ,可以用此指令去故意产生一个异常 ,(异常与中断有点类似, 过程相当于CPU从用户模式切换到特权模式, 然后跳转到内核代码中执行异常处理的代码。)
这种异常称为系统调用(System Call)
Linux的各种系统调用都是由int $0x80指令引发的,内核需要通过eax判断用户要调哪个系统调用。
.section .data
.section .text
.globl _start
_start:
movl $1, %eax # this is the linux kernel command
# number (system call) for exiting
# a program
movl $4, %ebx # this is the status number we will
# return to the operating system.
# Change this around and it will
# return different things to
# echo $?
int $0x80 # this wakes up the kernel to run
# the exit command