AT&T 汇编-12: 内联汇编

在涉及到一些对硬件的操作或者对性能有极致要求的时候,除了使用汇编函数之外还可以直接在 c 语言里编写汇编代码片段。

基本格式

一个最简单的什么都不做的 c 语言程序:

/* inline.c */

int main()
{
   asm ("nop");

   return 0;
}

内联汇编使用关键字 asm 表示在 c 语言中使用汇编代码:

asm ("assembly code");

使用命令

gcc -S inline.c

转换成汇编语言

    .file   "inline.c"
    .text
.globl main
    .type   main, @function
main:
    

阅读全文…

AT&T 汇编-11: 使用系统调用

前面使用系统调用 write() 来输入输出。一般来说,在 /usr/include/asm/unistd.h 可以找到可用的系统调用的定义(在我的机器上实际是 unistd_32.h):

...
#define __NR_restart_syscall      0
#define __NR_exit                 1
#define __NR_fork                 2
#define __NR_read                 3
#define __NR_write                4
#define __NR_open                 5
#define __NR_close                6
...

定义了系统调用和各自对应的值。

使用系统调用前要把对应的系统调用值放到 eax 中,再把需要的参数放到对应的位置,最后使用中断 int $0x80 使用系统调用。如果系统调用的参数小于 6 个,参数的顺序依次是:ebx,ecx,edx,esi,edi。如果系统调用的参数超过 6 个,则把参数内存位置的地址放到 …

阅读全文…

AT&T 汇编-10: 使用函数(2)

自己定义的汇编函数可以使用任意方式传递参数,但是如果每个函数都以不同方式传递参数则很容易造成混乱,所以一般都遵循 c 语言对参数的处理方式。

有些通用寄存器被 c 语言用作特殊的用途,如果在函数种需要修改这些寄存器需要把它们保存起来,在退出函数时再恢复原来的值:

+--------+------------------+
| 寄存器 |       作用       |
+--------+------------------+
|   ebx  |  指向全局偏移表  |
+--------+------------------+
|   edi  |    局部寄存器    |
+--------+------------------+
|   esi  |    局部寄存器    |
+--------+------------------+
|   ebp  | 作为堆栈基址指针 |
+--------+------------------+
|   esp  |  

阅读全文…

AT&T 汇编-9: 位操作

位操作是针对整数的二进制位进行的。

左移

用于左移的指令有两种:sal(向左算术移位)和shl(向左逻辑移位)。它们执行的操作相同,对于有符号和无符号整数的结果也一样。指令有 3 种不同的格式(以shl为例):

shl   destination
shl   %cl,  destination
shl   shift,   destination

destination 可以是 8 位,16 位或 32 位的值,根据不同的长度在 sal/shl 后附加不同的字母区分。第一种格式把 destination 的各个二进制位依次向左移动 1 位;第二种格式把 destination 的各个二进制位依次向左移动寄存器 cl 中指定的位数;第三种和第二种意义一样,只不过移动的位数由 shift 指定。

左移后,数值右边造成的空位用 0 填充,左边超出数据长度的位(最高有效位)会被暂时存放到进位标志(CF)中。

# shl.s

.section .rodata
msg:
   

阅读全文…

AT&T 汇编-6: 循环

loop 指令使用 ecx 作为计数器并且在每次执行的时候自动递减 ecx 的值,直到 ecx 为 0。loop 指令的格式是

loop location

其中 location 是要跳转的程序代码的标签。loop 指令只支持 8 位的偏移量,所以只能进行短跳转(跳转偏移量小于 128 字节)。

# loop.s

.section .rodata
msg:
   .asciz   "The value of ecx is %d.\n"

.section .text
.globl main
main:
   movl  $5,   %ecx

阅读全文…

AT&T 汇编-5: 分支跳转

很多时候代码都不是从头到尾顺序依次执行的,往往需要根据条件进行跳转,改变代码的执行流程。

无条件跳转

无条件跳转就一条很简单的 jmp 命令:

jmp   location

其中 location 是要跳转到的代码位置,通常由一个标签表示。标签就是一个标识符后加一个冒号,像一直在使用的 main 和 _start 都是标签。

# jmp.s

.section .rodata
msg1:
   .ascii   "I like this mm.\n"
msg2:
   .ascii   "I like that mm.\n"

.section .text
.globl _start
_start:
   movl  $4,      %eax  # system 

阅读全文…