汇编程序的Hello world

转自: http://www.cnblogs.com/orlion/p/5316519.html

​​​​​​原文链接:http://www.orlion.ga/989/

一、汇编程序的Hello world

 

x86 AT&T:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

.data  

msg:  

    .ascii "Hello world, hello AT&T asm!\n"  

    len = . - msg  

   

.text  

.global _start  

   

_start:  

    movl    $len,   %edx    # 显示的字符数  

    movl    $msg,   %ecx    # 缓冲区指针  

    movl    $1, %ebx    # 文件描述符  

    movl    $4, %eax    # 系统调用号,_write  

    int $0x80       # 系统调用  

   

    movl    $0, %ebx    # 传给_exit的参数  

    movl    $1, %eax    # 系统调用号,_exit  

    int $0x80       # 系统调用

然后汇编链接再执行:

汇编程序的Hello world

这段汇编相当于:

1

2

3

4

5

6

7

8

9

#include <unistd.h>

char msg[14] = "Hello,world!\n";

#define len 14

 

int main(void)

{

    write(1, msg, len);

    _exit(0);

}

    .data段有一个标号msg,代表字符串“Hello,world!\n”的首地址,相当于C程序的一个全局变量。在汇编指示.ascii定义的字符串末尾没有隐含的‘\0’。汇编程序中的len代表一个常量,它的值由当前地址减去符号msg所代表的地址得到,换句话说就是字符串“Hello,world!\n”的长度。现在解释一下这行代码中的.,汇编器总是从前到后把汇编代码转换成目标文件,在这个过程中维护一个地址计数器,当处理到每个段的开头时把地址计数器置成0,然后每处理一条汇编指示或指令就把地址计数器增加相应的字节数,在汇编程序中用.可以取出当前地址计数器的值,是一个常量。

    在_start中调了两个系统调用,第一个是write系统调用,第二个是以前讲过的_exit系统调用。在调write系统调用时,eax寄存器保存着write的系统调用号4,ebx、ecx、edx寄存器分别保存着write系统调用需要三个参数。ebx保存着文件描述符,进程中每个打开的文件都用一个编号来标识,成为文件描述符,文件描述符1表示标准输出,对应的C标准I/O库的stdout。ecx保存着输出缓冲区的首地址。edx保存着输出的字节数。write系统调用把从msg开始的len个字节写到标准输出。

    C代码中的write函数是系统调用的包装函数,其内部实现就是把传进来的三个参数分别赋给ebx、ecx、edx寄存器,然后执行movl $4,%eax和int $0x80两指令。这个函数不可能完全用C代码写,因为任何C代码都不会编译生成int指令,所以这个函数有可能完全用汇编写的,也有可能是C用内联汇编写的,甚至是一个宏定义。_exite函数野史如此。

分类: 汇编

上一篇:linux-boot-arch_x86_kernel_head_32.S


下一篇:【Hackathon】BSV编程马拉松冠军计划打造一个动态的比特币网络