GCC中启用intel风格的内联汇编
gcc中默认的内联汇编格式默认为AT&T格式,我们可以主动声明intel风格的内联汇编——asm(".intel_syntax noprefix\n"),编译时使用-masm=intel选项,此时源文件中的汇编代码就可以得到正确处理。以下为示例程序:
#include<stdio.h>
int main()
{
int a = 1,b = 2;
asm(".intel_syntax noprefix\n");
asm("mov dword ptr a,3\n");
a = a + b;
printf("%d\n",a);
return 0;
}
使用gcc进行编译:gcc -masm=intel asm_test.c -o asm_test
然而编译失败,输出错误提示:/usr/bin/ld: /tmp/ccmEXVmu.o: relocation R_X86_64_32S against undefined symbol `a' can not be used when making a shared
a是一个未定义的符号所以出错。分析原因,a是一个局部变量,存储位置在栈空间,编译器对变量a的引用是通过 rbp+偏移量 的方式进行的,所以我们对a的引用也要使用 rbp+偏移量的方式,关键问题是确定a在堆栈中的偏移量。
对于如下代码,
#include<stdio.h>
int main()
{
int a;
int b;
int c;
int d;
int f;
a = 10;
b = 10;
c = 10;
d = 10;
f = 10;
printf("%d\n",a);
return 0;
}
我们对其进行编译得到汇编代码:
.file "intel_asm.c"
.intel_syntax noprefix
.section .rodata
.LC0:
.string "%d\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
sub rsp, 32
mov DWORD PTR -20[rbp], 10
mov DWORD PTR -16[rbp], 10
mov DWORD PTR -12[rbp], 10
mov DWORD PTR -8[rbp], 10
mov DWORD PTR -4[rbp], 10
mov eax, DWORD PTR -20[rbp]
mov esi, eax
lea rdi, .LC0[rip]
mov eax, 0
call printf@PLT
mov eax, 0
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 6.2.0-5ubuntu12) 6.2.0 20161005"
.section .note.GNU-stack,"",@progbits
我们可以看到,对于局部变量a的是通过 -20[rbp] 来进行引用的,对于局部变量f是通过 -4[rbp] 进行引用的,而堆栈又是从高地址向低地址生长,这说明gcc对于局部变量的处理是先声明后如栈,这与vc的处理方式不同,通过查阅资料可知,这是由于gcc采用了一种名为SSP的堆栈保护技术导致的,我们使用-fno-stack-protector选项不使用该技术再次编译该文件:
.file "intel_asm.c"
.intel_syntax noprefix
.section .rodata
.LC0:
.string "%d\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
sub rsp, 32
mov DWORD PTR -4[rbp], 10
mov DWORD PTR -8[rbp], 10
mov DWORD PTR -12[rbp], 10
mov DWORD PTR -16[rbp], 10
mov DWORD PTR -20[rbp], 10
mov eax, DWORD PTR -4[rbp]
mov esi, eax
lea rdi, .LC0[rip]
mov eax, 0
call printf@PLT
mov eax, 0
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 6.2.0-5ubuntu12) 6.2.0 20161005"
.section .note.GNU-stack,"",@progbits
此时可以看到,对于变量a的引用已经是 -4[rbp] 了,这说明变量a先入栈。
现在修改我们的示例文件,由以上可知,对于变量a的引用应该是 -8[rbp]
#include<stdio.h>
int main()
{
int a = 1,b = 2;
asm(".intel_syntax noprefix\n");
asm("mov dword ptr [rbp -8],3\n");
a = a + b;
printf("%d\n",a);
return 0;
}
jyj6536@jyj6536-VirtualBox:~/文档/C语言2/2$ gcc -masm=intel asm_test.c -o asm_test
jyj6536@jyj6536-VirtualBox:~/文档/C语言2/2$ ./asm_test
5
结果正确