movl %eax, %edx # edx = eax 寄存器寻址 , eax寄存器里的数据参与计算
movl $0x123, %edx # edx = 0x123; 立即数寻址 , 数值0x123参与计算
movl 0x123, %edx # edx = *(int32_t*)0x123 直接寻址 , 0x123地址里的数值参与计算
movl (%ebx), %edx # edx = *(int32_t*)ebx 间接寻址 , ebx里的数值是地址,这个地址指向的数值参与计算
movl 4(%ebx), %edx # edx = *(int32_t*)(ebx+4) 变址寻址 , ebx里的数值+4 作为地址,这个地址指向的数值参与计算
pushl %eax ;
相当于{subl $4, %esp; movl %eax, (%esp); } , pushl 这个l 指Long,是32bits,intel栈是向下增长的,所以esp要减4. 参考函数栈EBP,ESP寄存器
popl %eax ;
相当于{movl (%esp), %eax; addl $4, $esp;}
call 0x12345 ;
相当于 { pushl %eip() ; movl $0x12345, %eip();} eip(*) 是不能被程序员直接修改的,只能通过指令,间接修改
汇编指令分析:
pushl $8 ; (假设ebp,esp指向同一地址)ebp 指针不变;esp减4,向下前进
movl %esp, %ebp ; ebp减4,和esp指向一致
pushl %esp ; esp减4,向下移动一位
pushl $8 ; esp减4,向下移动一位
addl $4, %esp ; esp加4,向上回退一位
popl %esp ; esp加4,向上回退一位
C程序编译成汇编
test1.c
int g(int x)
{
return x+3;
}
int f(int x) {
return g(x);
}
int main(void)
{
return f(8) + 1;
}
gcc -S -o test1.s test1.c -m32
命令说明
-S 编译成汇编,
-m32 编译成32位汇编, uname -a
可以看到所在平台是linux-64位,我们研究的是 32位汇编
-o 生成目标文件的文件名
test1.s 文件:
.file "test1.c"
.text
.globl g
.type g, @function
g:
.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
movl 8(%ebp), %eax
addl $3, %eax
popl %ebp
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size g, .-g
.globl f
.type f, @function
f:
.LFB1:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
subl $4, %esp
movl 8(%ebp), %eax
movl %eax, (%esp)
call g
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE1:
.size f, .-f
.globl main
.type main, @function
main:
.LFB2:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
subl $4, %esp
movl $8, (%esp)
call f
addl $1, %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE2:
.size main, .-main
.ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-36)"
.section .note.GNU-stack,"",@progbits
以".“开头的都是链接时的辅助信息,不实际执行,可以将以”."开头的命令直接省去。
执行过程演示:
c语言中内嵌汇编:
#include<stdio.h>
int main(void)
{
int input,output,temp;
input = 1;
__asm__ __volatile__ (
"movl $0 , %%eax;\n\t" // $0 是立即数
"movl %%eax , %1;\n\t" // %1 是二个输出参数,按照公式:"__asm__(汇编语句模板: 输出部分: 输入部分: 破坏描述部分)", %0 是output, %1是temp
"movl $2 , %%eax;\n\t"
"movl %%eax , %0;\n\t" // %0 是第一个输出数 output
:"=m"(output),"=m"(temp)
:"r"(input)
:"eax"
);
printf("%d %d\n", temp, output);
return 0;
}
%%eax 第一个”%“是转义
内嵌汇编语法如下:
__asm__(汇编语句模板: 输出部分: 输入部分: 破坏描述部分)
共四个部分:汇编语句模板,输出部分,输入部分,破坏描述部分,各部分使用“:” 格开,汇编语句模板必不可少,其他三部分可选,如果使用了后面的部分,而前面部分为空, 也需要用“:”格开,相应部分内容为空。例如:
__asm__ __volatile__("cli": : :"memory")