1. 一般套路
分两布,编译,linux下有两种常用的编译器,gnu的as和nasm,两者的区别是前者用AT&T语法,后者用了intel的语法,个人更喜欢gnu的语法一些。链接,链接分静态链接和动态链接两种。再加一个gdb调试器,基本上齐活了。
2. nasm例子
|
|
直接抄<汇编语言基于linux环境>第五章的例子,调用了linux的systemcall ,也就是系统调用,eax是4,就是write系统调用。write的参数如下:
- EAX contains the system call value.
- EBX contains the file descriptor to write to.
- ECX contains the start of the string.
- EDX contains the length of the string.
ebx是文件句柄,1就是标准输出。
ecx是字符串的开始位置,这里是将EatMsg的地址传进去
edx是字符串的长度,这里也是用了equ的伪指令EatLen
全部传进去调用int 80H就调用传说中的的write系统调用了。
之后再调用退出系统调用,结束程序运行。ebx存储返回值,shell 里面可以用echo $?来查看。
|
|
-g 用于生成调试信息,-F 指定stabs格式,可以方便的用gdb调试。
之后是链接,用标准链接工具ld:
|
|
运行就是一个标准输出:
|
|
3.as例子
跟nasm差不多:
|
|
这里再抄一下<汇编语言程序设计>里面的例子,cpuid ,可以看到gas的语法明显和intel的不一样,最明显的差别是源操作数和目的操作数的位置是相反的。
这个调用了cpuid 的1号指令。将cpuid信息返回在ebx,ecx,edx三个寄存器中。
- EBX contains the low 4 bytes of the string.
- EDX contains the middle 4 bytes of the string.
- ECX contains the last 4 bytes of the string.
movl将三个值分别送到output的指定位置,也就是’xxxxxxxxxxxx’中去。然后调用write系统调用来输出。最后是一个退出的系统调用。
|
|
4.section区域
一般linux程序需要定义三个区域,
- .data区域,定义已初始化变量
- .bss 定义为初始化变量
- .text 正文区域,里面要用.globl 指定开始点。
区域根据elf格式而来,不止这三个。linux下nasm和as都适用~
|
|
5.ia32下编程
上面提到的环境都能在ia32的模式下运行的很好,也就是说不用再切到dos下去调试。开个虚拟机就可以愉快的玩耍,很适合汇编的学习。实模式和保护模式一个最大的区别就是内存寻址是一个flat方式,可以直接引用内存。不用加段。