AT&T 汇编-1: hello, world

第一个汇编程序

# hello.s
# display a string "Hello, world."

.section .rodata
msg:
   .ascii "Hello, world.\n"

.section .text
.globl _start
_start:
   movl  $4,    %eax    # system call
   movl  $1,    %ebx    # file descriptor
   movl  $msg,  %ecx    # string address
   movl  $14,   %edx    # string length
   int   $0x80

   movl  $1, %eax
   movl  $0, %ebx
   int   $0x80

运行下面的命令生成可执行文件 hello:

as hello.s -o hello.o
ld hello.o -o hello

然后运行这个程序:

./hello

即可看到输出:

Hello, world.

程序分析

程序的第 1, 2 行

# hello.s
# display a string "Hello, world."

“#”后的内容是注释,直到行尾。

.section .rodata

表示接下来的内容存放在数据段,并且这些内容是只读的(“ro”是“read only”的缩写)。一般来说,数据段(.data)是存放程序员自己定义变量的地方,文本段(.text)是存放代码的地方。

接下来的两行:

msg:
   .ascii "Hello, world.\n"

定义了一个字符串“Hello, world.\n”(不包括双引号),“msg”是一个标记,表示字符串的起始地址。“.ascii”表示后面数据的类型是不以 ‘\0’ 结尾的字符串,如果需要为字符串添加一个 ‘\0’ 可以使用“.asciz”。

再下一行

.section .text

说明该行以下的内容存放在文本段。

.globl _start
_start:

声明了一个开始标记“_start”,这相当于 c/c++ 里的 main() 函数,程序从这个标记开始往下执行。“.globl”声明的标记可被外部程序访问。

movl  $4, %eax # system call

mov 系列指令是最常用的用于传送数据的指令。根据数据长度不同分别在 mov 后添加不同的字母加以区分,例如 movl 传送的是 32 位的数据,movw 是 16 位,movb 是 8 位,而且不同长度的数据对应的寄存器名字也不一样。mov 指令的格式是:

mov source, destination

和 intel 汇编的操作数顺序正好相反。

AT&T 汇编的格式有点奇怪,立即数前要加一个“$”,而寄存器前加“%”。这条语句的意思是把立即数 4 传送到寄存器 eax 中,也就是说把 eax 的值设为 4。

eax 是一个 32 位的寄存器,如果想使用 16 位或 8 位的寄存器可以使用 ax 或 ah/al,它们的结构如下所示:

                     | <---   ax  ---> |
                     |<- ah ->|<- al ->|
   +--------+--------+--------+--------+
   |        |        |        |        |
   +--------+--------+--------+--------+
   |       <-----   eax   ----->       |

除了 eax 外,还有 ebx,ecx 等寄存器,这些寄存器一般情况下可作为通用寄存器,但是在某些指令中会使用这些寄存器传递参数,例如本例。

movl  $1,   %ebx     # file descriptor
movl  $msg, %ecx     # string address
movl  $14,  %edx     # string length

中间一句的“$msg”表示 msg 的地址。前面提过 msg 表示的是字符串“Hello, world.\n”的起始地址,这里是把字符串的地址放到寄存器 ecx 中。

int $0x80

这个是一个软中断,中断号是 0x80,执行由 eax 指定的系统调用,调用所需要的参数分别存放在 ebx,ecx 和 edx。在这里调用了 Linux 提供的 4 号系统调用(即write()),把内容输出到标准输出,即“write(1, msg, 14)”。

最后的

movl  $1, %eax
movl  $0, %ebx
int   $0x80

把返回值 0 放到寄存器 ebx 中,调用 1 号系统调用(exit() 函数),程序结束。

如果最后没有调用 exit() 会出现段错误,不知道这是为什么。

发表于 2011年4月17日
  1. yorktsai
    2012年3月23日 18:46 | #1

    你写的总结非常棒,很容易看明白,谢谢了。。。

  2. ichabod
    2016年9月30日 16:10 | #2

    你总结的很好,多谢

发表评论

XHTML: 您可以使用这些标签: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>