c语言与汇编混合编程例子,C语言与汇编混合编程

您所在的位置:网站首页 汇编c语言混合编程怎么用汇编定义变量 c语言与汇编混合编程例子,C语言与汇编混合编程

c语言与汇编混合编程例子,C语言与汇编混合编程

2024-06-10 13:55| 来源: 网络整理| 查看: 265

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