C/C++与汇编混合编程

news2024/11/29 20:50:44

1. C/C++调用汇编

C/C++想调用汇编代码必须要注意名称修饰的问题

名称修饰(name decoration): 一种标准的C/C++编译技术, 通过添加字符来修改函数名, 添加的字符指明了每个函数参数的确切类型。主要是为了支持函数重载, 但对于汇编来说其问题在于, C/C++编译器让链接器去找被修饰过的名称而非原始名称

名称修饰说白了就是C/C++源代码经过编译器编译后, 函数和变量名称发生了变化, 链接器会去找变化后的名字而非源码中定义的名字。
影响名称修饰的主要因素如下:

  • 编程语言, 比如C和C++名称修饰就不同
  • 调用约定, 比如C和STDCALL的名称修饰不同

举个例子, C和C++之间的名称修饰就是不同

a. C语言中的名称修饰格式以及C与汇编混合编程

源码如下:
在这里插入图片描述
看一下其生成obj文件:
在这里插入图片描述
发现经过VS的C编译器编译后main和Add名称前多了下划线。由于C语言默认的函数调用约定是C调用约定。所以这就是C语言使用C调用约定下的名称修饰。

_name

接下去将Add的调用约定改成STDCALL
在这里插入图片描述
再来查看一下生成的obj文件, 发现其名称修饰方式发生了改变:
在这里插入图片描述
所以C语言STDCALL调用约定下的名称修饰方式是:

_name@n

这里的n代表压入栈帧参数的大小, 由于Add参数参别是2个int类型, 在x86下也就是8字节大小, 所以经过C编译器名称修饰后就变成了

_Add@8

总结一下, C编译器编译C源码时, 默认情况下函数使用C调用约定, 除非强制指定其他调用约定, 其编译后生成的obj文件中, 名称修饰的方法如下:

C stdcall: _name@n
C cdecl: _name

接下来看一下汇编语言, 首先使用C调用约定, 经过汇编生成obj文件。
在这里插入图片描述
查看winhex发现:
在这里插入图片描述
不出乎意料, FindMax和main函数都使用了C调用方式的名称修饰, 但是ExitProcess却使用了STDCALL的名称修饰规则, 这很正常, 因为微软的API都使用STDCALL。
由于C语言和汇编生成的obj目标文件中的名称修饰都是相同的, 所以可以得出结论:

C可以直接调用使用C调用约定下的汇编代码, 无需任何改变

下面实验一下:
这是汇编源码:
在这里插入图片描述
将汇编生成的obj文件包含到项目内, 测试发现C语言调用C调用约定下的汇编没有问题:
在这里插入图片描述
如果说汇编使用STDCALL调用约定汇编生成对应的obj文件, 然后让C来进行调用, 结果就会发现这个熟悉的链接错误:
在这里插入图片描述
这个原因已经很明显了, 因为C语言默认使用C调用约定, 编译后生成的是_name格式的函数名, 当汇编使用STDCALL调用约定时, 生成的是_name@n格式的函数名, 当链接时自然就无法找到名称了。
所以可以得出结论:

C可以直接调用使用STDCALL调用约定下的汇编代码, 会出现无法解析外部符号的链接错误

b. C++中的名称修饰格式以及C++与汇编混合编程

使用C++编写一个程序, C++默认也使用C调用约定:
在这里插入图片描述
查看其生成的obj目标文件
在这里插入图片描述
可以发现经过C++编译器编译后, C调用约定下Add函数生成了一种非常奇怪的形式, 这主要是为了实现重载而做的。而main函数永远是C调用约定不会被C++编译器改变。

这也就意味着C和C++其实也使不可以互相调用的

因为如果你要用C++调用C代码。假设都使用C调用约定, C代码经C编译器生成了obj文件, 里面的名称修饰是:

_name

而C++编译器编译代码生成的obj里面使用的名称修饰是:

?Add@@YAHHH@Z

当链接时, C++去找**?Add@@YAHHH@Z**结果只有_Add, 这是肯定不可能找到的。

下面把Add函数变成STDCALL函数调用约定试试看:
在这里插入图片描述
可以发现其名称修饰变成了如下:

?Add@@YGHHH@Z // stdcall
?Add@@YAHHH@Z // C

得出结论:

C++下C和STDCALL调用约定有区别, 但是区别不大, 把A变成了G

如果想要在C++下调用汇编代码, 只要把C++的名称修饰转换成C的就可以了。
所以只要C++能调用C, 也就意味着C++可以调用汇编, 事实上也确实如此, 在C++源文件中, 函数添加extern "C"即可让C++函数使用C的名称修饰方法
在这里插入图片描述
C++源码生成obj, 放入winhex内便可发现, C++使用了C的名称修饰方式, 不管是什么调用约定, extern "C"都会让C++使用C的调用约定。
在这里插入图片描述
使用同样的方法就可以实现C++调用汇编代码了。
在这里插入图片描述

2. C/C++调用汇编的另一种方式: 内联汇编

这种方式只能在x86下进行, 并没有什么特别的地方:
在这里插入图片描述
这里给一个例子, 是一个对称xor加密的小例子:

#include <iostream>
#include <windows.h>
#include <tchar.h>

#define FILEBLK		(0x1000)

using namespace std;

VOID CryptoBlock(PBYTE pbBuf, DWORD dwBufSize, UCHAR bKey)
{
	__asm
	{
		mov esi, pbBuf
		mov ecx, dwBufSize 
		mov bl, bKey
	L0:
		xor BYTE PTR [esi], bl
		inc esi 
		loop L0
	}
	return;
}

BOOLEAN SymFileCrypto(LPCSTR pcszFilePathName, UCHAR bKey)
{
	HANDLE hFile = INVALID_HANDLE_VALUE;
	HANDLE hNewFile = INVALID_HANDLE_VALUE;
	BOOLEAN fOk = FALSE;
	LARGE_INTEGER liFileSize = { 0 };
	int iTotalBlk = 0;
	BYTE bBuf[FILEBLK] = { 0 };
	char szTmpFileName[] = "TmpFile";

	DWORD dwReaded = 0;
	DWORD dwWritten = 0;

	__asm
	{
		// 参数检测
		mov esi, pcszFilePathName
		test esi, esi
		jz Ending
		// 打开文件
		push NULL
		push FILE_ATTRIBUTE_NORMAL
		push OPEN_EXISTING
		push NULL
		push 0
		push FILE_ALL_ACCESS
		push esi
		call CreateFile
		// 文件句柄检查
		cmp eax, -1
		jne Next1 
		jmp Ending 
	Next1:
		// 保存文件句柄
		mov hFile, eax
		// 获取文件大小
		lea eax, liFileSize
		push eax
		push hFile
		call GetFileSizeEx
		// 计算总块数
		mov eax, liFileSize.LowPart
		mov edx, liFileSize.HighPart
		mov ebx, FILEBLK
		div ebx
		test edx, edx 
		jz Next2
		inc eax 
	Next2:
		mov iTotalBlk, eax
		// 创建新文件
		push NULL
		push FILE_ATTRIBUTE_NORMAL
		push CREATE_ALWAYS
		push NULL
		push 0
		push FILE_ALL_ACCESS
		lea eax, szTmpFileName
		push eax
		call CreateFile
		// 文件句柄检查
		cmp eax, -1
		jne Next3
		jmp Ending
	Next3:
		mov hNewFile, eax 
	Crypto:
		// 读取文件内容
		push NULL 
		lea eax, dwReaded
		push eax 
		mov eax, FILEBLK
		push eax 
		lea eax, bBuf 
		push eax
		push hFile 
		call ReadFile 
		test eax, eax 
		jz Ending 
		// 加解密
		xor eax, eax 
		mov al, bKey 
		push eax 
		push dwReaded 
		lea eax, bBuf
		push eax
		call CryptoBlock
		// 写入文件内容
		push NULL
		lea eax, dwWritten 
		push eax 
		push dwReaded 
		lea eax, bBuf 
		push eax
		push hNewFile 
		call WriteFile
		test eax, eax 
		jz Ending 
		mov ecx, iTotalBlk
		dec ecx 
		mov iTotalBlk, ecx
		test ecx, ecx 
		jnz Crypto
		mov fOk, TRUE
	}

Ending:
	__asm
	{
		cmp hNewFile, -1
		jz Next4 
		push hNewFile 
		call CloseHandle 
		mov hNewFile, NULL
		Next4:
		cmp hFile, -1
		jz Next5
		push hFile 
		call CloseHandle 
		mov hFile, NULL
	Next5:
		xor eax, eax 
		mov al, fOk
		test eax, eax 
		jz Next6
		// 删除源文件
		mov eax, pcszFilePathName
		push eax
		call DeleteFile 
		// 改名
		mov eax, pcszFilePathName
		push eax 
		lea eax, szTmpFileName
		push eax 
		call MoveFile 
		Next6:
		mov esp, ebp
		pop ebp 
		ret 
	}
}


int main(int argc, char **argv)
{
	if (argc != 3)
	{
		printf("usage: %s file key\r\n", argv[0]);
		return(-1);
	}

	if (SymFileCrypto(argv[1], argv[2][0]))
	{
		printf("成功\r\n");
	}
	else
	{
		printf("失败\r\n");
	}

	return(0);
}

(完)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1055121.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

毅速课堂:3D打印随形水路设计应注意什么?

随形水路是一种基于3D打印技术的新型模具冷却水路&#xff0c;能有效提高冷却效率、缩短冷却周期、提升产品良率、提高生产效率、 与传统的水路设计相比&#xff0c;随形水路更加贴合模具型腔表面&#xff0c;能够更加均匀地分配冷却水&#xff0c;使模具各部分的冷却效果得到有…

Day_17> 动态内存管理

目录 1.为什么存在动态内存分配&#xff1f; 2.动态内存函数的介绍 malloc calloc realloc 3.常见的动态内存错误 1.对NULL指针的解引用操作 2.对动态开辟空间的越界访问 3.对非动态开辟内存使用free释放 4.使用free释放一块动态开辟内存的一部分 5.对同一块动态内…

BUUCTF reverse wp 66 - 70

[SWPU2019]ReverseMe 反编译的伪码看不明白, 直接动调 这里显示"Please input your flag", 然后接受输入, 再和32进行比较, 应该是flag长度要求32位, 符合要求则跳转到loc_E528EE分支继续执行 动调之后伪码可以读了 int __cdecl main(int argc, const char **arg…

5大文件管理操作,Python自动化办公,整明白了

大家好&#xff0c;这里是程序员晚枫。 在更新开源项目&#xff1a;python-office的这1个多月里&#xff0c;又发现了一些新需求&#xff0c;今天整理出来&#xff0c;分享给大家~ 全是自动化办公的常用工具&#xff0c;网友&#xff1a;早知道就好了 1、批量压缩文件夹 电脑…

Koa处理请求数据

在开发中&#xff0c;后端接收到请求参数后&#xff0c;需要解析参数。请求分为很多种类型&#xff0c;比如常见的get和post。 请求参数 Koa本身可以解析get请求参数&#xff0c;不能解析post请求参数。例如&#xff1a; router.get(/api/get/userInfo, async (context) >…

链表经典面试题(二)

返回中间结点 1.中间结点的题目2.中间结点的图文分析3.中间结点的基本代码4.中间结点的优化代码 1.中间结点的题目 2.中间结点的图文分析 方法1&#xff1a;先求整体长度&#xff0c;再除以2&#xff0c;所得到的就是中间结点 方法2&#xff1a;双指针法&#xff0c;快指针走两…

图像语义分割 U-Net图像分割网络详解

图像语义分割 U-Net图像分割网络详解 简介原始论文中的网络结构在医学方面的应用pytorch官方实现以DRIVE眼底血管分割数据集训练U-Net语义分割网络模型U-Net网络训练损失函数 简介 U-Net网络非常的简单&#xff0c;前半部分就是特征提取&#xff0c;后半部分是上采样。在一些文…

SWOT分析法和个人职业规划

在企业发展的过程中&#xff0c;有一套理论比较靠谱&#xff0c;受到许多大企业的热烈追捧&#xff0c;这套理论倒不是充满神秘感的大道理&#xff0c;而是我们常见的SWOT分析法。S代表了优势&#xff0c;W则是劣势&#xff0c;O乃是英文中的机会&#xff0c;T也就是威胁的意思…

【深度学习实验】卷积神经网络(六):自定义卷积神经网络模型(VGG)实现图片多分类任务

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 三、实验内容 0. 导入必要的工具包 1. 构建数据集&#xff08;CIFAR10Dataset&#xff09; a. read_csv_labels&#xff08;&#xff09; b. CIFAR10Dataset 2. 构建模型&#xff08;FeedForward&…

iOS自动化测试方案(二):Xcode开发者工具构建WDA应用到iphone

文章目录 一、环境准备1.1、软件环境1.2、硬件环境1.3、查看版本 二、安装WDA过程2.7、构建失败&#xff0c;这类错误有很多&#xff0c;比如在选择开发者账号后&#xff0c;就会提示:Failed to register bundle identifier表示应用唯一注册失败2.9、第二个错误&#xff0c;完全…

MySql出错点

一、DDL 1.修改表&#xff0c;添加新的字段时&#xff0c;不要加引号 2.在修改表中字段的类型时&#xff0c;会发生数据截断。 像DATETIME 转化为 TIME 二、DML 1.插入和删除的注意点 2.可以通过 select 来协助插入 3.

Linux之进程间通信

进程间通信 进程间通信介绍进程间通信目的进程间通信本质进程间通信分类 管道管道概念匿名管道pipe函数管道特点 命名管道创建命名管道匿名管道与命名管道的区别用命名管道实现serve&client通信 system V进程间通信system V共享内存共享内存数据结构共享内存的建立与释放共…

Anaconda Jupyter

&#x1f64c;秋名山码民的主页 &#x1f602;oi退役选手&#xff0c;Java、大数据、单片机、IoT均有所涉猎&#xff0c;热爱技术&#xff0c;技术无罪 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; 获取源码&#xff0c;添加WX 目录 前言An…

五、3d场景的卡片展示的创建

在我们3d的开发中&#xff0c;对某一些建筑和物体进行解释说明是非常常见的现象&#xff0c;那么就不得不说卡片的展示了&#xff0c;卡片展示很友好的说明了当前物体的状态&#xff0c;一目了然&#xff0c;下面就是效果图。 它主要有两个方法来实现&#xff0c;大量的图片建议…

Cinema 4D 2024更新, 比旧版速度更快!

Cinema 4D 2024 for Mac更新至v2024.0.2版本&#xff0c;其中Cinema 4D核心得到了全面优化&#xff0c;增强了可调的Pyro模拟、增强了真实镜头耀斑和色彩校正工作流程。 Cinema 4D 2024变得更加强大&#xff0c;在交互式播放方面有了巨大的性能改进&#xff0c;对刚性体模拟进行…

毛玻璃动画交互效果

效果展示 页面结构组成 从上述的效果展示页面结构来看&#xff0c;页面布局都是比较简单的&#xff0c;只是元素的动画交互比较麻烦。 第一个动画交互是两个圆相互交错来回运动。第二个动画交互是三角绕着圆进行 360 度旋转。 CSS 知识点 animationanimation-delay绝对定位…

CISSP学习笔记:PKI和密码学应用

第七章 PKI和密码学应用 7.1 非对称密码学 对称密码系统具有共享的秘钥系统&#xff0c;从而产生了安全秘钥分发的问题非对称密码学使用公钥和私钥对&#xff0c;无需支出复杂密码分发系统 7.1.1 公钥与私钥 7.1.2 RSA&#xff08;兼具加密和数字签名&#xff09; RSA算法…

Minecraft我的世界部署教程

部署 费了老鼻子劲才搞懂如何部署&#xff0c;对新人实在是太不友好了。所以总结一下。 这里选用 PaperMC Veloity&#xff0c;使用 docker compose 部署。 结构 首先搞清楚服务器部署原理&#xff0c;有两个东西。 Minecraft 服务端Minecraft 服务代理 服务核心常见的主…

【算法挨揍日记】day09——704. 二分查找、34. 在排序数组中查找元素的第一个和最后一个位置

704. 二分查找 704. 二分查找 题目描述&#xff1a; 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 解题思路&…

基于Java的网上摄影工作室网站设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…