C++内联汇编(英特尔编译器):LEA和MOV在Windows和Linux中表现不同

 最最时尚搭配攻略_ 发布于 2023-01-11 12:22

我正在转换一个巨大的Windows DLL以在Windows和Linux上工作.dll有很多用于视频操作的汇编(和SS2指令).

现在,使用Windows上的Intel ComposerXE-2011和Linux上的Intel ComposerXE-2013 SP1中包含的英特尔编译器,可以在Windows和Linux上编译代码.

但是,在尝试调用函数指针时,执行会在Linux中崩溃.我在gdb中跟踪代码,实际上函数指针并没有指向所需的函数(而在Windows中则没有).几乎所有其他工作正常.

这是代码序列:

...
mov    rdi, this
lea    rdx, [rdi].m_sSomeStruct
...
lea    rax, FUNCTION_NAME                # if replaced by 'mov', works in Linux but crashes in Windows
mov    [rdx].m_pfnFunction, rax
...
call   [rdx].m_pfnFunction               # crash in Linux

哪里:

1)'this'有一个struct成员m_sSomeStruct.

2)m_sSomeStruct有一个成员m_pfnFunction,它是一个指向函数的指针.

3)FUNCTION_NAME是同一编译单元中的自由函数.

4)所有这些纯组装函数都声明为裸.

5)64位环境.

让我最困惑的是,如果我用'mov'指令替换应该将函数地址加载到rax中的'lea'指令,它在Linux上工作正常但在Windows上崩溃.我在Visual Studio和gdb中都跟踪了代码,显然在Windows"lea"中给出了正确的函数地址,而在Linux'mov'中则是这样.

我试着查看英特尔组装参考,但没有找到太多帮助我(除非我没有找对地方).

任何帮助表示赞赏.谢谢!


编辑更多详情:

1)我尝试使用方括号

lea    rax, [FUNCTION_NAME]

但这并未改变Windows和Linux中的行为.

2)我在gdb和Windows中查看了反汇编程序,似乎都给出了我实际编写的相同指令.更糟糕的是,我尝试将两个lea/ mov一个接一个地放在一起,当我在gdb的反汇编中查看它们时,在#符号之后的指令后打印的地址(我假设是将要存储的地址)在寄存器中)实际上是相同的,并且不是函数的正确地址.

它在gdb反汇编程序中看起来像这样

lea  0xOffset1(%rip), %rax   # 0xSomeAddress
mov  0xOffset2(%rip), %rax   # 0xSomeAddress

其中两个(SomeAddress)是相同的,并且两个偏移都是由lea和mov指令之间的相同差异关闭的,但不知何故,当我在每次执行后检查寄存器的内容时​​,mov似乎放入了正确的值! !

3)成员变量m_pfnFunction的类型为LOAD_FUNCTION,定义为

typedef void (*LOAD_FUNCTION)(const void*, void*);

4)函数FUNCTION_NAME在.h(在命名空间内)声明为

void FUNCTION_NAME(const void* , void*);

并在.cpp中实现

__declspec(naked) void namespace_name::FUNCTION_NAME(const void* , void*)
{
...
}

5)我尝试通过添加来关闭优化

#pragma optimize("", off)

但我仍然有同样的问题

1 个回答
  • 另外,我怀疑在后一种情况下链接到DLL的方式是FUNCTION_NAME是一个实际将被设置为函数的加载地址的内存位置.也就是说,它是函数的引用(或指针),而不是入口点.

    我熟悉Win(而不是其他),我已经看到了如何调用函数

    (1)生成到该地址的CALL,该地址在链接时填写.对于同一模块中的函数来说足够正常,但如果在链接时发现它在不同的DLL中,则导入库是一个存根,链接器将其视为与任何正常函数相同,但只不过是JMP [?? ??].导入函数的地址表被安排为具有在保存地址的字段之前编码JMP指令的字节.该表在DLL加载时填充.

    (2)如果编译器知道该函数将在不同的DLL中,它可以生成更高效的代码:它将间接CALL编码到位于导入表中的地址.(1)中显示的存根函数具有与之关联的符号名称,包含该地址的实际字段也具有符号名称.它们都以功能命名,但具有不同的"装饰".通常,程序可能包含对两者的修正引用.

    所以,我猜想你使用的符号名称与一个编译器上的stub函数匹配,并且(它以类似的方式工作)匹配另一个平台上的指针.也许汇编程序将unmangled名称分配给一个或另一个,具体取决于它是否被声明为已导入,并且两个工具链上的选项不同.

    希望有所帮助.我想你可以在调试器中查看运行时,看看上面是否有助于你解释地址及其周围的东西.

    2023-01-11 12:27 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有