C与汇编混合编程(1)
2016-03-19 23:31
169 查看
前情提要
每个搞过竞赛的同学可能都想象过通过内嵌汇编来提高程序效率,然而对于绝大多数同学来说,可能也只是开开玩笑而已,毕竟CCF的考纲里面明确写了不许内嵌汇编。我就是众多只在嘴上说说的人之一,反正中学六年我最终还是没有写过一句内嵌汇编。
当然这只是因为我基本不会汇编(捂脸)
今天由于某些特殊原因(解释起来太长),我又一次想到了在编写C程序的时候使用汇编,然后就开始了今天晚上的人在囧途之旅~
为方便叙述,本文中代码一律使用C而不是C++,系统环境采用Linux(Windows下出问题别来找我)
内嵌汇编?
纵使我是一个渣渣,我也知道想要在C中使用汇编有两种方式:在C的代码里面内嵌汇编
把汇编编译成单独文件,然后再链接起来
本着从易到难的原则,我决定先从内嵌汇编试起。
可是谁告诉你内嵌汇编简单了?
查完了某度,刚准备动手,猛然注意到文章中说的都是VC。常识告诉我,巨硬会用它自己的汇编器MASM,这显然会与我现在使用的gcc有区别。
于是又一次某度过后,我发现gcc的汇编器GAS用的是AT&T风格的汇编,跟我略微会那么一点点的x86汇编完全不一样。
没有办法,硬着头皮凭借自己瞎撸的本事靠感觉写出几行AT&T风格的汇编。
结果呢?
结果还用问吗?!!当然是CE啊!
链接汇编
使用NASM
在意识到我根本就没有办法在短时间内写出正确的AT&T风格汇编代码之后,我只能问某度怎么把x86汇编配合gcc使用,然后就看到一个老朋友——NASM。讲真,NASM虽然和MASM有点不同,可它至少是x86汇编器啊,我看到了希望。
原理很简单,用NASM编译汇编代码,再把它链接到C编译出来的.o文件上就可以了。
在C中使用汇编中的函数
实现混合编程的一个重要方面就是要实现C代码和汇编代码的数据、函数共享。对于我来说,最重要的就是能让C访问汇编的函数,这样就可以通过汇编来提高程序效率。在C代码中需要写的确实很简单,只要像往常一样extern以下就可以了。举个例子:
extern int add(int a,int b);
在汇编中我们需要做的就是将标签声明成global的:
global add
接下来的一个问题是,C中调用函数的参数是怎样传给汇编的?
说实话我根本不知道……只能百度。在被各种信息坑了无数次后,终于得出结论:
C在调用函数时,先将参数逆序压栈,再转到函数的地址上
讲真,具体是啥样的我们还是下次再研究吧
所以说,我们在汇编中的函数所要做的第一件事就是把参数从栈中取出来。
注意一下32位和64位可能不兼容的问题……
如果使用的是64位系统,在链接的时候出问题几乎是必然的。原因在于,nasm是32位的汇编器,而gcc在64位系统下会生成64位的代码。32位和64位的程序是无法链接在一起的。解决方法有两个:
换用64位汇编器(同时也要写64位汇编)
让gcc用32位模式编译
平心而论,最佳选择应该是第一个。然而我太懒……就选择了后者。后一种方式就是在编译的时候加上-m32而已。
当然,你可能还是会面临一堆报错,那是因为你的gcc没有32位的依赖文件。安装一个依赖包就可以了。
sudo apt-get install libc6-dev-i386
代码
其实这才是最重要的东西是吧仅仅只是实现了一个输出字符串的功能
//1.c #include <stdio.h> #include <string.h> extern void dispstr(const char*,const int); void puts_asm(const char* str){ dispstr(str,strlen(str)); } int main(){ puts_asm("This is a message printed by asm.\n"); puts("This is a message printed by C."); return 0; }
;dispstr.asm [section .text] global dispstr dispstr: push ebp mov ebp,esp sub esp,0F0h mov edx,[ebp+12] ;字符串的长度 mov ecx,[ebp+8] ;首字符的地址 ;因为寄存器中存的是地址,所以要加方括号 mov ebx,1 mov eax,4 int 80h leave ;作用等于下面两句 ;mov esp,ebp ;pop ebp ret
编译方法:
all: nasm -f elf dispstr.asm -o dispstr.o gcc -o 1 1.c dispstr.o -m32
运行结果:
后记
其实我对汇编一窍不通,写代码纯靠百度大法虽然编程作业还没写,但却有一种谜一般的从容
虽然周三数分小测我还没复习,但却有一种谜一般的从容
相关文章推荐
- 如何组织构建多文件 C 语言程序(二)
- 如何写好 C main 函数
- Lua和C语言的交互详解
- 关于C语言中参数的传值问题
- 简要对比C语言中三个用于退出进程的函数
- 深入C++中API的问题详解
- 基于C语言string函数的详解
- C语言中fchdir()函数和rewinddir()函数的使用详解
- C语言内存对齐实例详解
- C语言编程中统计输入的行数以及单词个数的方法
- C语言自动生成enum值和名字映射代码
- 使用C语言判断英文字符大小写的方法
- c语言实现的带通配符匹配算法
- C语言实现顺序表基本操作汇总
- C语言中计算正弦的相关函数总结
- 使用C语言详解霍夫曼树数据结构
- 探讨C语言的那些小秘密之断言
- C语言实现BMP转换JPG的方法
- 深入探讨C语言中局部变量与全局变量在内存中的存放位置
- C语言查找数组里数字重复次数的方法