C与汇编混合编程(1)

前情提要

每个搞过竞赛的同学可能都想象过通过内嵌汇编来提高程序效率,然而对于绝大多数同学来说,可能也只是开开玩笑而已,毕竟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 
#include 

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

运行结果:
这里写图片描述


后记

  • 其实我对汇编一窍不通,写代码纯靠百度大法
  • 虽然编程作业还没写,但却有一种谜一般的从容
  • 虽然周三数分小测我还没复习,但却有一种谜一般的从容

你可能感兴趣的:(随便玩玩,汇编)