32位汇编第七讲,混合编程,内联汇编

          32位汇编第七讲,混合编程

博客园IBinary原创 QQ:2510908331  博客连接:http://www.cnblogs.com/iBinary/

转载请注明出处,谢谢

混合编程的概念,有时候我们会想,C语言可不可以调用汇编的函数,或者反过来调用

或者说C语言里面内部直接内联汇编去编写.

可以实现,静看怎么实现

一丶C语言调用汇编语言的函数

1.创建工程和代码

①创建VC++控制台程序

FILE(文件) - NEW (新建)

然后我们打开源文件,一级一级展开,找到我们的main函数

那么我们现在要调用汇编写的,那么我们用汇编写一个代码

②,创建汇编程序

创建汇编程序,这个比较简单,我们新建个文件夹,里面新建一个文本文档,后缀名改为ASM,然后用RadAsm打开,开始编写代码

使用RadAsm编写,这样比较快

编写我们的汇编代码

,注意下方的end结束符号,我们并没有指明开始位置是MyAdd,也就是说这个汇编程序,只能编译

编译出的OBJ 和我们上边写的程序的OBJ 一起连接(上面的程序也是编译,不连接)

看下汇编代码

.386

.model flat,stdcall

option casemap:none

.const

.data

.code

  MyAdd proc c ,n1:DWORD,n2:DWORD

    mov eax,n1

    add eax,n2

    ret

  MyAdd endp

End

博客园IBinary原创 QQ:2510908331  博客连接:http://www.cnblogs.com/iBinary/

③丶C/cpp文件调用汇编中的MyAdd函数

1.先编译汇编程序,产生obj文件

将此obj文件复制到我们的C/c++的目录下

2.修改C/c++程序,调用我们的增加函数

C/C++代码如下,注意这样写你只能编译,不能连接,只能先生成OBJ

博客园IBinary原创 QQ:2510908331  博客连接:http://www.cnblogs.com/iBinary/

2.连接程序使用的几个步骤

我们要想使用上面几个程序,有多中方式去掉用,分别是

①丶手工编译C/C++程序,产生.obj文件,然后和汇编的.obj连接起来

编译我们的.cpp文件,产生.boj文件

命令是 cl /c 文件名

,然后把上面的MyAdd.obj(汇编程序编译的)

汇编程序的编译可以通过RadAsm,如果配置好了就直接F5编译即可,如果没配置好,可以手工用命令行编译,这里不讲解了,以前课程都有讲怎么编译,还有配置RadAsm

现在我们拿到了两个.obj文件

开始连接成一个.exe文件

手工连接

Link C/C++文件名.obj 汇编文件名.obj

理论上来说连个obj文件谁在前谁在后都没有区别,但是现在是我们的C/C++程序要调用 MyAdd,所以C/C++在前

打开CMD定位到我们的目录下(怎么打开百度搜索)

你可以直接文件夹上面输入CMD 回车,则会在当前的目录下,注意这里为了演示命令的截图

把两个obj文件拷贝了出来

开始连接

成功生成

打开程序校验一下

可以调用了

②丶将汇编程序的.obj文件,放到C/C++工程的目录下,利用工程特性,直接连接

我们可以把obj放到VC++中,这样我们可以直接编译连接使用,不用手工编译连接了

因为VC++6.0的Bug,我使用了一个插件修复,本来可以直接在 File(文件) - > Open(打开)的

解决VC的Bug,这里我直接提供一个Dll,把Dll放在VC++的目录的上一层,Addins中

操作步骤

1.右键属性打开文件位置

2.返回上一层目录

3.进入Addins文件夹下,把FileTool.dll拷贝进去

拷贝FileTool.dll

4.重新打开VC++6.0(注意管理员权限打开)

在菜单中点击  Tools(工具) -> Customize(定制) -> Add-ins And Macro Files

选中即可,如果再有问题,可以百度搜索,DLL会打包

上面解决了一个BUG,那么现在看下我们的工程中是否有了MyAdd.obj

现在编译连接则可以执行

③将obj定义为lib去使用

上面我们直接使用的obj,但是这样不太好,因为obj一多,工程文件就多了,不好维护(当然目的不再这里)

那么我们把obj定义为lib

怎么定义?,可以使用vc++自带的lib工具,如果配置了环境变量,则直接输入cmd,跳转到目录下,把MyAdd.obj生成为lib

输入lib 则会出现这个帮助,如果没有配置环境变量,那么输出lib则会出错,不过一般默认配置了,如果不会配置,请看前边的配置环境,RadAsm IDE的配置,里面内容一样

先介绍一下Lib工具的使用把

这个工具很简单,  lib 选项(可选)  文件名(可选)

例如我们要把MyAdd.obj变为lib,则语法是

Lib MyAdd.obj...... (...代表了有多个obj 依次后面填写即可,注意中间不要加逗号,隔开即可)

生成了

遍历lib 看下有多少obj,着用list语法

语法

Lib /list lib名称

,,为了测试C2ASM我也打包了

现在我们可以使用Lib去编程了

现在只需要我们的工程中包含这个lib则可以使用,不用再把MyAdd.obj添加到工程中了

博客园IBinary原创 QQ:2510908331  博客连接:http://www.cnblogs.com/iBinary/

二丶汇编调用C写的函数

汇编调用C写的函数,那么是一样的,因为.obj都是一样的

首先看下汇编代码,汇编代码应该挺熟悉了,(不熟悉,看下以前的)

.386

.model flat,stdcall

option casemap:none

include msvcrt.inc

includelib msvcrt.lib   ;C库的动态的静态使用

includelib MyAdd.lib  ;lib调用,加载自己的lib

MyAdd proto c n1:dword, n2:dword

.const

    g_szFmt db "1+2=%d", 0dh, 0ah, 0

    g_szPause db "pause", 0

.data

.code

main proc c argc:dword, argv:dword

    invoke MyAdd, 1, 2

    invoke crt_printf, offset g_szFmt, eax

    invoke crt_system, offset g_szPause

    mov eax, 0

    ret

main endp

end main

注意,因为我们这里使用printf了,我们是动态的静态使用,什么是静态的动态使用,前边已经说过了,不会的请看下前边的文章

那么现在我们新建个.c文件,里面单独写一个函数(不用工程了)

编译这个文件,生成.obj,然后和汇编程序的.obj连接,但是注意现在是汇编程序的.obj在前

因为汇编调用这个的obj

当然这两个obj我们也可以打包成lib使用,上面的汇编程序就是用的打包好的lib

所以这几个步骤就不写了,生成lib给汇编程序使用,至于手工的编译汇编程序,连接汇编程序其实不建议去用了,随着编译器的提升,以后加的选项越来越多

手工生成lib

Lib MyAdd.obj   (MyAdd.obj 是手工编译的MyAdd.c的文件)

使用RadAsm编译连接1.asm程序

博客园IBinary原创 QQ:2510908331  博客连接:http://www.cnblogs.com/iBinary/

三丶汇编DLL的使用

像我们上面的生成的lib只能给C/C++使用,但是别的程序不见得能使用

所以我们写一个汇编的DLL,给C/C++程序使用

至于C/C++调用dll,那么有两种方式

一种是使用静态方式,就是加载dll的静态lib库(这个lib库中保存的是dll名称)

然后添加个头文件去使用

另一种是动态的loadlibrary,和GetprocessAddress去使用,动态的加载dll去使用

这里简单说下第一种,至于动态使用有开发知识的应该会调用,如果没开发知识也没有关系

因为咱们这个是汇编,不是再讲开发,(虽然开发很重要),但是咱们今天的主要内容不是上面所有的,压轴的在最下面

1.首先利用RadAsm新建一个dll的空工程,填写以下代码

汇编代码:

.386

.model flat,stdcall

option casemap:none

include windows.inc

.const

.data

.code

MyAdd Proc n1:DWORD, n2:DWORD

     mov eax, n1

     add eax, n2                ;写一个我们的MyAdd函数

    ret

MyAdd endp

DllMain proc hModule:HINSTANCE , dwReason:DWORD, lpvReserved:LPVOID

    mov eax, TRUE

    ret

DllMain endp

end DllMain       ;注意DLL的入口点要指定

然后在DEF文件导出我们的定义的代码

编译连接之后则会生成DLL,和保存DLL信息的lib

那么我们的工程可以使用了

静态使用

结果

至于代码,会上传课堂资料中

博客园IBinary原创 QQ:2510908331  博客连接:http://www.cnblogs.com/iBinary/

四丶压轴的内联汇编

1.内联汇编简单了解

首先我们会想,上面虽然完成的 汇编和C的互相调用,也解决的跨语言的DLL调用

但是觉着还是不好,为什么,因为可能我想写的汇编代码就那么一点,我还得生成DLL

或者生成lib

那么我们突发奇想,可不可以在C/C++中写汇编代码

比如我们写个int 3的中断指令

C/C++代码

#include "stdafx.h"

typedef  int (*PFN)(int n1,int n2); //定义函数指针

int main(int argc, char* argv[])

{

//写二进制代码

    unsigned char Code[] = {0xCC, 0x55,  0x8B,  0xEC, 0x8B,
                                      0x45, 0x08, 0x03, 0x45, 0x0c, 0xc9, 0xC3};

    int result = ((PFN)(void*)Code)(1, 2);

    printf("%d",result);

    return 0;

}

看到这个代码是不是晕了,没关系,谁叫我们是学汇编的,用OD调试看下

因为是Dbg程序,所以int 3指令对齐了,我们发现确实是断点到这里停止了,我们需要价格ret

直接打开int 3.exe看看是否会崩溃,如果崩溃则用OD调试,看下到底出现了什么情况

调试看看

发现是int3断点断下来了,我们发现,刚在我们写入的代码其实是二进制代码我们把它当做函数执行,也就是Call一下,我们写入的是一个加法的函数

难道汇编代码都要这样写吗

所以VC++6.0为我们提供了一个语法,叫做

_asm  注意前边是一个下划线

也可以加块语句去写

但是一般我们不这样写,因为这样会破坏寄存器环境所以开始和结束我们要保存一下寄存器的环境

Pushad 和push s是保存所有寄存器环境,和所有标志寄存器标志

我们看下VC++6.0的汇编到底做了什么

(在VC++6.0中内联汇编,可以下短点,然后ALT +8跳转到VC的汇编中查看)

是一样的

2.内联汇编调用函数

一丶普通调用的无参数调用

上面我们知道的怎么写内联汇编了,那么下边我们则可以把这个内联汇编定位为函数

写个ADD函数把

首先我们工程封装成一个函数

我们可以直接这样写,因为编译器内部已经帮我们压栈,平栈...各种东西都帮我们做了

我们一会ALT + 8看下

现在我们要调用了,因为返回值问题,是怎么返回我们不知道,虽然我们知道是放在eax中

但是如果你改成int,那么我们要写为 return eax?显然是不可以的,而如果在_asm中

写ret,那么这个函数不知道你返回了所以先定义为void,我们一会解决返回值问题

调用:

我们要自己push,自己Call,又因为MyAdd是C调用约定,所以我们要自己平栈,

我们看下汇编代码

这个是我们调用的代码

我们看下MyAdd的时候里面做了什么

我们发现其实我们的核心代码就是两句,但是编译器帮我们做了很多事

从第一个循环申请局部变量上面就不说了,前边讲过了

(保存栈底,开辟局部空间,保存环境.....)

主要看下面,恢复完寄存器信息之后就开始释放局部变量空间,然后在Debug版本下会检测栈

是否平衡,如果不平衡,就弹个错误框,最后ret的时候,因为压入了两个参数还没有平栈

所以上面我们需要自己平栈,一个参数4个字节,所以+8

看下结果

2.解决普通的调用有返回值的问题

上面我们如果调用,那么就要自己内联,自己调用,但是很不方便,所以我们加个返回值

直接调用也可以,编译器智慧给警告,因为编译器支持这个语法

调用

直接调用即可

看下结果

那么就完美解决了

博客园IBinary原创 QQ:2510908331  博客连接:http://www.cnblogs.com/iBinary/

3.(inline)裸函数

我们这样想,上面编译器帮我们做了很多事情,我们不知道,我们有的时候这个函数就行自己用我们的写的代码

那么这个时候就可以用裸函数了,有关键字

_declspec(naked) ....

看下反汇编是什么

可以看到,明显的编译器没有帮我们做申请局部变量空间....等等一系列的操作

但是我们就要自己去写了

看下结果

 

4.内联调用API

如果内联了,那么就不支持invoke这种伪指令去操作了,都是真实的去写汇编代码

调用其实挺简单,加上数据段,和函数名就可以的,但是注意函数的头文件要包含(Windows.h)

5.内联寻找函数的参数

我们上面调用一个Add函数,自己还要计算

mov eax,[ebp +8]

Sub eax,[ebp + 0ch]

但是其实这些我们的函数有参数了,我们可以使用参数来弄

比如

Mov eax,n1

Sub eax,n2 这样去写就行

反正怎么像伪指令怎么写,不支持也要想办法优化.

不然参数多了就容易混乱

博客园IBinary原创 QQ:2510908331  博客连接:http://www.cnblogs.com/iBinary/

课堂资料:

链接:http://pan.baidu.com/s/1jIJzsyE 密码:dtu4

时间: 2024-10-04 06:17:44

32位汇编第七讲,混合编程,内联汇编的相关文章

linux平台学x86汇编(十八):内联汇编

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 使用汇编语言笔编程最常见的方式是在高级语言(C和C++)程序内编写汇编函数,这种吧汇编语言直接写到C和C++语言程序内的技术称为内联汇编. GNU的C编译器使用asm关键字指出使用汇编语言编写的源代码段落.asm段的基本格式如下: asm("as code"): 括号中的汇编指令必须在括号,指令超过一条的话必须使用新的行分隔汇编语言代码每一行,因为编译器逐字地取得a

Android漫游记(5)---ARM GCC 内联汇编烹饪书(附实例分析)

原文链接(点击打开链接) 关于本文档 GNU C编译器针对ARM RISC处理器,提供了内联汇编支持.利用这一非常酷炫的特性,我们可以用来优化软件代码中的关键部分,或者可以使用针对特定处理的汇编处理指令. 本文假定,你已经熟悉ARM汇编语言.本文不是一篇ARM汇编教程,也不是C语言教程. GCC汇编声明 让我们从一个简单的例子开始.下面的一条ARM汇编指令,你可以添加到C源码中. /* NOP example-空操作 */ asm("mov r0,r0"); 上面的指令,讲r0寄存器的

x86平台转x64平台关于内联汇编不再支持的解决

x86平台转x64平台关于内联汇编不再支持的解决     2011/08/25   把自己碰到的问题以及解决方法给记录下来,留着备用!   工具:VS2005  编译器:cl.exe(X86 C/C++)  ml64.exe(X64 ASM64) 前提:X86下内联汇编是嵌在函数当中实现的 在X86平台下,可以轻松的在C/C++代码中嵌入汇编代码,称其为"内联汇编",使用"__asm{}"语法即可,比较简单,这里不做介绍.当你在X86平台下,由于性能和速度的要求,需

【转贴】GCC内联汇编基础

原文作者 Sandeep.S英文原文 [https://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html] 本文将介绍GCC编译环境下,在C语言代码中嵌入汇编代码的基本方法.阅读本文需要您具备80X86汇编语言和C语言的基础知识.为了使中文描述更加清楚自然,翻译过程中加入了稍许解释和意译部分. 简介 版权/反馈/勘误/感谢等信息.[^ 1][^ 1]:这里信息价值不大,没有翻译.具体参加原文:https://www.ibiblio.

嵌入式Linux ARM汇编(七)——C语言与ARM汇编混合编程

嵌入式Linux ARM汇编(七)--C语言与ARM汇编混合编程 在嵌入式系统开发中,目前使用的主要编程语言是C和汇编.在大规模的嵌入式软件中,例如含有OS,大部分的代码都是用C编写的,主要是因为C语言的结构比较好,便于人的理解,而且有大量的支持库.但是很多地方还是要用到汇编语言,例如开机时硬件系统的初始化,包括CPU状态的设定,中断的使能,主频的设定,以及RAM的控制参数及初始化,一些中断处理方面也可能涉及汇编.另外一个使用汇编的地方就是一些对性能非常敏感的代码块,这是不能依靠C编译器的生成代

64位内联汇编

#define  Base_Pople 0x9cd654int Call_DaZuo=0x0044e000; //打坐 void DaZuo() { _asm { mov ecx,[Base_Pople] mov ecx,[ecx] mov ecx,[ecx+0x70] mov ecx,[ecx+0x1ec] mov ecx,[ecx+0x8] mov ecx,[ecx+0x200] call Call_DaZuo } } 内联汇编中不能直接用常量

最牛X的GCC 内联汇编

导读 正如大家知道的,在C语言中插入汇编语言,其是Linux中使用的基本汇编程序语法.本文将讲解 GCC 提供的内联汇编特性的用途和用法.对于阅读这篇文章,这里只有两个前提要求,很明显,就是 x86 汇编语言和 C 语言的基本认识. 1. 简介 1.1 版权许可 Copyright (C) 2003 Sandeep S. 本文档自由共享:你可以重新发布它,并且/或者在遵循自由软件基金会发布的 GNU 通用公共许可证下修改它:也可以是该许可证的版本 2 或者(按照你的需求)更晚的版本. 发布这篇文

GCC内联汇编入门

原文为GCC-Inline-Assembly-HOWTO,在google上可以找到原文,欢迎指出翻译错误. 中文版说明 由于译者水平有限,故译文出错之处,还请见谅.C语言的关键字不译,一些单词或词组(如colbber等)由于恐怕译后词不达意,故并不翻译,由下面的单词表代为解释,敬请见谅. 英文原文中的单词和词组: operand:操作数,可以是寄存器,内存,立即数. volatile:易挥发的,是C语言的关键字. constraint: 约束. register: 本文指CPU寄存器. asm:

[翻译] GCC 内联汇编 HOWTO

GCC 内联汇编 HOWTO v0.1, 01 March 2003. * * * 本 HOWTO 文档将讲解 GCC 提供的内联汇编特性的用途和用法.对于阅读这篇文章,这里只有两个前提要求,很明显,就是 x86 汇编语言和 C 语言的基本认识. [TOC] 原文链接与说明 http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html 本翻译文档原文选题自 Linux中国 ,翻译文档版权归属 Linux中国 所有 1. 简介 1.