c语言与汇编混合编程例子,C语言与汇编混合编程 |
您所在的位置:网站首页 › 汇编c语言混合编程怎么用汇编定义变量 › c语言与汇编混合编程例子,C语言与汇编混合编程 |
extern声明外部变量 我们在c1.c文件中定义一个变量 int i = 3; 在c2.c文件中使用这个变量 #include int main(){ printf("%d\n",i); } 编译c2.c的时候会报错,因为在编译阶段,可见性仍局限于各自的文件,编译c2.c文件时觉察不到c1.c文件中已经定义了i。 虽然编译器的目光不够长远,但是我们可以给它提示,帮助它来解决上面出现的问题。这就是extern的作用了。 #include extern int i; int main(){ printf("%d\n",i); } extern的原理很简单,就是告诉编译器:“你现在编译的文件中,有一个标识符虽然没有在本文件中定义,但是它是在别的文件中定义的全局变量,你要放行!” gcc -c c1.c gcc -c c2.c gcc c1.o c2.o -o test 程序正常运行。 C语言与汇编相互调用 基于上面的原理,我们完全可以将一个变量或一个函数用汇编语言写,在c语言中用extern声明一下,就可以调用啦。 C和汇编参数传递规则: 规定参数在4个以内,依次对应r0-r3寄存器。参数在4个以外,用栈(满减栈)传递。 返回值传递,规定使用r0寄存器。 举个例子,在a.s中用汇编定义一个函数: .globl _add _add: pushq%rbp movq%rsp, %rbp movl%edi, -4(%rbp) movl%esi, -8(%rbp) movl-4(%rbp), %eax addl-8(%rbp), %eax popq%rbp retq 然后在b.c中用extern声明add是外部函数: #include extern int add(int a,int b); int main(){ int i; i = add(5,6); printf("%d\n",i); } 编译 gcc -c a.s gcc -c b.c gcc a.o b.o -o test 程序可以正常执行。 如果你有疑惑,可以将b.c转成汇编: gcc -S -masm=intel -fno-asynchronous-unwind-tables b.c -o b.s 在汇编中可以看到,c语言调用add函数无非就是call _add,若用汇编实现这个函数,只需要汇编的标号为_add即可。 .section__TEXT,__text,regular,pure_instructions .build_version macos, 10, 16sdk_version 11, 0 .intel_syntax noprefix .globl_main ## -- Begin function main .p2align4, 0x90 _main: ## @main ## %bb.0: pushrbp movrbp, rsp subrsp, 16 movedi, 5 movesi, 6 call_add movdword ptr [rbp - 4], eax movesi, dword ptr [rbp - 4] leardi, [rip + L_.str] moval, 0 call_printf xorecx, ecx movdword ptr [rbp - 8], eax ## 4-byte Spill moveax, ecx addrsp, 16 poprbp ret ## -- End function .section__TEXT,__cstring,cstring_literals L_.str: ## @.str .asciz"%d\n" .subsections_via_symbols 同样的,汇编调用C语言也是这个道理。 内嵌汇编 GCC 提供了内联汇编语法,可以直接在C语言中使用汇编指令。GCC扩展内联汇编的基本格式是: asm volatile ( Assembler Template : Output Operands /* optional */ : Input Operands /* optional */ ) 例如: int main(){ int a=10, b; asm volatile ( "movl %1, %%eax; \n" "movl %%eax, %0;" :"=r"(b) /* output */ :"r"(a) /* input */ ); } 汇编的意思是将变量a的值放到eax寄存器,然后将eax的值放到b变量中。 %0,%1指输入输出列表中的变量,本例中%0代表b,%1代表a。由于这些样板操作数的前缀使用了“%”,因此,在用到具体的寄存器时就在前面加两个“%”,如%%eax。 输入输出列表中的r是指约束条件,或者说是“变量类型”,输出的约束条件前面要加"=",常用约束条件列表: 字母 含义 m 内存单元 i 常数(0~31) a, b, c, d 寄存器eax, ebx, ecx,edx q,r 动态分配的寄存器 g eax,ebx,ecx,edx或内存变量 数字"0" 指定与第0个变量相同的约束 最后,Intel汇编与AT&T汇编格式不同,他们是可以替换的,这里给出参考: +------------------------------+------------------------------------+ | Intel Code | AT&T Code | +------------------------------+------------------------------------+ | mov eax,1 | movl $1,%eax | | mov ebx,0ffh | movl $0xff,%ebx | | int 80h | int $0x80 | | mov ebx, eax | movl %eax, %ebx | | mov eax,[ecx] | movl (%ecx),%eax | | mov eax,[ebx+3] | movl 3(%ebx),%eax | | mov eax,[ebx+20h] | movl 0x20(%ebx),%eax | | add eax,[ebx+ecx*2h] | addl (%ebx,%ecx,0x2),%eax | | lea eax,[ebx+ecx] | leal (%ebx,%ecx),%eax | | sub eax,[ebx+ecx*4h-20h] | subl -0x20(%ebx,%ecx,0x4),%eax | +------------------------------+------------------------------------+ |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |