在有些情况下,我们不得不需要C和汇编同时上阵,各显神通。BootLoader和Kernel就是比较典型的例子,本文将就C语言和汇编语言混合编程做些简略说明。需要说明的是,这里所说的混合编程,并不是C语言中嵌入汇编,如需要相关资料,请自行查找。
知识回顾:GCC编译流程是,先将C语言翻译成汇编语言(*.s),再编译成目标文件(*.o),最后执行连接,将目标文件连接成可执行文件。C语言编程中,经常需要调用函数,函数通常由三部分组成:函数名、参数、返回值。在混合编程中,需要注意的就是函数参数的传递和返回值的传递,这里直接给出结果,默认的情况下GCC是用栈来传递参数的,并且参数的压栈顺序是从最后一个参数向前依次压栈,而返回值保存在寄存器%eax中,在GCC的扩展中可以用附加属性__attribute__((regparm(n)))来指定有几个参数用寄存器传递,但是用寄存器传递的参数个数不能多余3个。用寄存器进行参数传递时,从第一个参数开始依次用寄存器%eax, %edx, %ecx来传递参数,未能用寄存器传递的参数,将从最后一个参数开始依次压栈,用栈来进行传递,返回值依旧保存在寄存器%eax中。
Linux下汇编:
Linux下的汇编用的是AT&T格式的I386汇编,要想一个汇编文件中的某个Label在其它文件中可见,则必须用.globl _lablel_name导出。
C语言下的函数和汇编下的Label:实际上我们在C语言中定义的函数或者是全局变量在C语言翻译成汇编语言的后,和汇编语言导出的Label是等同的。但是名称可能发生变化,比如说C语言中的一个函数为void test(void),翻译成汇编语言就可能为_test,test,GCC在当前的Linux系统中,是翻译成test的,在Windows平台上的MinGwin中的GCC还是如以前一样,翻译成_test,至于为什么采用后者,一说为让交叉索引程序更容易生成交叉索引。
C语言调用汇编语言的例子:File: main.c
#include
int main(void) { int ret;
ret = test(4); printf("%d\n", ret);
return 0; }
|
File: test.s
.text .globl test test: push %ebp mov %esp, %ebp
mov 8(%esp), %eax imull 8(%esp), %eax
mov %ebp, %esp pop %ebp ret
|
汇编语言调用C语言的例子:File:main.c
#include
int test2(int val) { return val * val; }
int main(void) { int ret;
ret = test(4); printf("%d\n", ret);
return 0; }
|
File: test.s
.text .globl test test: push %ebp mov %esp, %ebp
mov 8(%esp), %eax imull 8(%esp), %eax push %eax call test2
mov %ebp, %esp pop %ebp ret
|
阅读(2922) | 评论(2) | 转发(0) |