手机站
网通分站
电信主站
密 码:
用户名:
当前位置 : 主页>网站运营>建站经验>列表

Linux 汇编语言研发指南 AT

来源:互联网 作者:west263.com 时间:2008-04-16
西部数码-全国虚拟主机10强!40余项虚拟主机管理功能,全国领先!双线多线虚拟主机南北访问畅通无阻!免费赠送企业邮局,.CN域名,自助建站480元起,免费试用7天,满意再付款! P4主机租用799元/月.月付免压金!

若想获得 ALD 支持的任何调试命令的周详列表,能够使用 help 命令:



ald> help

Commands may be abbreviated.

If a blank command is entered, the last command is repeated.

Type `help <command>' for more specific information on <command>.



General commands

attach         clear          continue       detach         disassemble

enter          examine        file           help           load

next           quit           register       run            set

step           unload         window         write



Breakpoint related commands

break          delete         disable        enable         ignore

lbreak         tbreak


五、系统调用

即便是最简单的汇编程式,也难免要用到诸如输入、输出连同退出等操作,而要进行这些操作则需要调用操作系统所提供的服务,也就是系统调用。除非您的程式只完成加减乘除等数学运算,否则将很难避免使用系统调用,事实上除了系统调用不同之外,各种操作系统的汇编编程往往都是很类似的。

在 Linux 平台下有两种方式来使用系统调用:利用封装后的 C 库(libc)或通过汇编直接调用。其中通过汇编语言来直接调用系统调用,是最高效地使用 Linux 内核服务的方法,因为最终生成的程式无需和任何库进行链接,而是直接和内核通信。

和 DOS 相同,Linux 下的系统调用也是通过中断(int 0x80)来实现的。在执行 int 80 指令时,寄存器 eax 中存放的是系统调用的功能号,而传给系统调用的参数则必须按顺序放到寄存器 ebx,ecx,edx,esi,edi 中,当系统调用完成之后,返回值能够在寄存器 eax 中获得。

任何的系统调用功能号都能够在文档 /usr/include/bits/syscall.h 中找到,为了便于使用,他们是用 SYS_<name> 这样的宏来定义的,如 SYS_write、SYS_exit 等。例如,经常用到的 write 函数是如下定义的:



ssize_t write(int fd, const void *buf, size_t count);


该函数的功能最终是通过 SYS_write 这一系统调用来实现的。根据上面的约定,参数 fb、buf 和 count 分别存在寄存器 ebx、ecx 和 edx 中,而系统调用号 SYS_write 则放在寄存器 eax 中,当 int 0x80 指令执行完毕后,返回值能够从寄存器 eax 中获得。

或许您已发现,在进行系统调用时至多只有 5 个寄存器能够用来保存参数,难道任何系统调用的参数个数都不超过 5 吗?当然不是,例如 mmap 函数就有 6 个参数,这些参数最后都需要传递给系统调用 SYS_mmap:



void  *  mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);




当一个系统调用所需的参数个数大于 5 时,执行int 0x80 指令时仍需将系统调用功能号保存在寄存器 eax 中,所不同的只是全部参数应该依次放在一块连续的内存区域里,同时在寄存器 ebx 中保存指向该内存区域的指针。系统调用完成之后,返回值仍将保存在寄存器 eax 中。

由于只是需要一块连续的内存区域来保存系统调用的参数,因此完万能够像普通的函数调用相同使用栈(stack)来传递系统调用所需的参数。但要注意一点,Linux 采用的是 C 语言的调用模式,这就意味着任何参数必须以相反的顺序进栈,即最后一个参数先入栈,而第一个参数则最后入栈。假如采用栈来传递系统调用所需的参数,在执行 int 0x80 指令时还应该将栈指针的当前值复制到寄存器 ebx中。

六、命令行参数

在 Linux 操作系统中,当一个可执行程式通过命令行启动时,其所需的参数将被保存到栈中:首先是 argc,然后是指向各个命令行参数的指针数组 argv,最后是指向环境变量的指针数据 envp。在编写汇编语言程式时,很多时候需要对这些参数进行处理,下面的代码示范了如何在汇编代码中进行命令行参数的处理:

例3. 处理命令行参数



# args.s

.text

.globl _start

        

_start:

        popl	靫		# argc



vnext:

        popl	靫		# argv

        test 	靫, 靫      # 空指针表明结束

        jz	exit



        movl	靫, 離

        xorl	韝, 韝

strlen:

        movb	(離), %al

        inc	韝

        inc	離

        test	%al, %al

        jnz	strlen

        movb	, -1(離)



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

        movl	, 離        # 文档描述符(stdout) 

        int	x80



        jmp	vnext



exit:

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

        xorl	離, 離      # 退出代码

        int 	x80

		

        ret




七、GCC 内联汇编

用汇编编写的程式虽然运行速度快,但研发速度很慢,效率也很低。假如只是想对关键代码段进行优化,或许更好的办法是将汇编指令嵌入到 C 语言程式中,从而充分利用高级语言和汇编语言各自的特点。但一般来讲,在 C 代码中嵌入汇编语句要比"纯粹"的汇编语言代码复杂得多,因为需要解决如何分配寄存器,连同如何和C代码中的变量相结合等问题。

GCC 提供了很好的内联汇编支持,最基本的格式是:



__asm__("asm statements");




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