n1cef1sh's Blog

参考链接: 《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