转载自:IBM developerWorks 中国网站


肖文鹏(xiaowp@263.net)
北京理工大学电脑系硕士研究生
2003 年 7 月

section:disp(base, index, scale)

而在 Intel 汇编格式中,内存操作数的寻址方式为:



section:[base   index*scale   disp]


由于 Linux 工作在保护模式下,用的是 32 位线性地址,所以在计算地址时不用考虑段基址和偏移量,而是采用如下的地址计算方法:



disp   base   index * scale


下面是一些内存操作数的例子:

AT&T 格式Intel 格式
movl -4(雙), 陎mov eax, [ebp - 4]
movl array(, 陎, 4), 陎mov eax, [eax*4 array]
movw array(離, 陎, 4), %cxmov cx, [ebx 4*eax array]
movb , %fs:(陎)mov fs:eax, 4

三、Hello World!

真不知道打破这个传统会带来什么样的后果,但既然任何程式设计语言的第一个例子都是在屏幕上打印一个字符串 "Hello World!",那我们也以这种方式来开始介绍 Linux 下的汇编语言程式设计。

在 Linux 操作系统中,您有很多办法能够实现在屏幕上显示一个字符串,但最简洁的方式是使用 Linux 内核提供的系统调用。使用这种方法最大的好处是能够直接和操作系统的内核进行通讯,无需链接诸如 libc 这样的函数库,也无需使用 ELF 解释器,因而代码尺寸小且执行速度快。

Linux 是个运行在保护模式下的 32 位操作系统,采用 flat memory 模式,现在最常用到的是 ELF 格式的二进制代码。一个 ELF 格式的可执行程式通常划分为如下几个部分:.text、.data 和 .bss,其中 .text 是只读的代码区,.data 是可读可写的数据区,而 .bss 则是可读可写且没有初始化的数据区。代码区和数据区在 ELF 中统称为 section,根据实际需要您能够使用其他标准的 section,也能够添加自定义 section,但一个 ELF 可执行程式至少应该有一个 .text 部分。下面给出我们的第一个汇编程式,用的是 AT&T 汇编语言格式:

例1. AT&T 格式



#hello.s 

.data                    # 数据段声明

        msg : .string "Hello, world!\n" # 要输出的字符串

        len = . - msg                   # 字串长度



.text                    # 代码段声明

.global _start           # 指定入口函数

        

_start:                  # 在屏幕上显示一个字符串

        movl $len, 韝  # 参数三:字符串长度

        movl $msg, 靫  # 参数二:要显示的字符串

        movl , 離    # 参数一:文档描述符(stdout) 

        movl , 陎    # 系统调用号(sys_write) 

        int  x80       # 调用内核功能

        

                         # 退出程式

        movl ,離     # 参数一:退出代码

        movl ,陎     # 系统调用号(sys_exit) 

        int  x80       # 调用内核功能


初次接触到 AT&T 格式的汇编代码时,很多程式员都认为太晦涩难懂了,没有关系,在 Linux 平台上您同样能够使用 Intel 格式来编写汇编程式:

例2. Intel 格式





; hello.asm 

section .data            ; 数据段声明

        msg db "Hello, world!", 0xA     ; 要输出的字符串

        len equ $ - msg                 ; 字串长度



section .text            ; 代码段声明

global _start            ; 指定入口函数



_start:                  ; 在屏幕上显示一个字符串

        mov edx, len     ; 参数三:字符串长度

        mov ecx, msg     ; 参数二:要显示的字符串

        mov ebx, 1       ; 参数一:文档描述符(stdout) 

        mov eax, 4       ; 系统调用号(sys_write) 

        int 0x80         ; 调用内核功能



                         ; 退出程式

        mov ebx, 0       ; 参数一:退出代码

        mov eax, 1       ; 系统调用号(sys_exit) 

        int 0x80         ; 调用内核功能


上面两个汇编程式采用的语法虽然完全不同,但功能却都是调用 Linux 内核提供的 sys_write 来显示一个字符串,然后再调用 sys_exit 退出程式。在 Linux 内核源文档 include/asm-i386/unistd.h 中,能够找到任何系统调用的定义。

四、Linux 汇编工具

Linux 平台下的汇编工具虽然种类很多,但同 DOS/Windows 相同,最基本的仍然是汇编器、连接器和调试器。

1.汇编器

汇编器(assembler)的作用是将用汇编语言编写的源程式转换成二进制形式的目标代码。Linux 平台的标准汇编器是 GAS,他是 GCC 所依赖的后台汇编工具,通常包含在 binutils 软件包中。GAS 使用标准的 AT&T 汇编语法,能够用来汇编用 AT&T 格式编写的程式:

文章整理:西部数码--专业提供域名注册虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!