linux - 有没有办法在 linux 平台上编译微软风格的内联汇编代码?
问题描述
正如标题中提到的,我想知道有没有办法在 linux 操作系统(例如 ubuntu)中编译微软风格的内联汇编代码(如下所示)。
_asm{
mov edi, A;
....
EMMS;
}
示例代码是内联汇编代码的一部分,可以使用 cl.exe 编译器在 win10 上成功编译。有没有办法在linux上编译它?我是否必须以 GNU c/c++ 风格重写它(即 __asm__{;;;})?
解决方案
有没有办法在 linux 平台上编译微软风格的内联汇编代码?
对的,这是可能的。有点儿。
对于 GCC,您必须同时使用 Intel 和 AT&T 语法。由于问题 24232,它不适用于 Clang,内联汇编操作数不适用于 .intel_syntax和问题 39895,错误:使用内联 asm 的表达式中的未知标记。
这是模式。汇编器模板使用.intel_syntax
. 然后,在您的 asm 模板结束时,您切换回.att_syntax
模式,以便它处于编译器生成的其余 asm 的正确模式。
#include <cstddef>
int main(int argc, char* argv[])
{
size_t ret = 1, N = 0;
asm __volatile__
(
".intel_syntax noprefix ;\n"
"xor esi, esi ;\n" // zero RSI
"neg %1 ;\n" // %1 is replaced with the operand location chosen by the compiler, in this case RCX
"inc %1 ;\n"
"push %1 ;\n" // UNSAFE: steps on the red-zone
"pop rax ;\n"
".att_syntax prefix ;\n"
: "=a" (ret) // output-only operand in RAX
"+c" (N) // read-write operand in RCX
: // no read-only inputs
: "%rsi" // RSI is clobbered: input and output register constraints can't pick it
);
return (int)ret;
}
如果您使用任何内存操作数,这将不起作用,因为例如,编译器会将 AT&T 语法替换4(%rsp)
为模板而不是[rsp + 4]
.
这也仅在您不使用gcc -masm=intel
. 否则,当 GCC 发出 Intel 语法时,您会将汇编器置于 AT&T 模式。因此,使用.intel_syntax noprefix
会破坏您在 GCC 中使用任一语法的能力。
mov edi, A;
我帮助的代码不像你展示的那样在汇编器中使用变量。我不知道它与 Intel 风格的 ASM 配合得如何(很差?)。我知道不支持 MASM 样式语法。
您可以使用asmSymbolicNames
. 有关详细信息,请参阅 GCC扩展 ASM HowTo。
但是,要转换为 GCC 可以使用的东西,您只需要使用位置参数:
__asm__ __volatile__
(
".intel_syntax noprefix ;\n"
"mov edi, %0 \n"; // inefficient: use a "D" constraint instead of a mov
...
".att_syntax prefix ;\n"
: : "r" (A) : "%edi"
);
或者更好的是,首先使用"D"
约束来询问 EDI / RDI 中的变量。如果 GNU C 内联 asm 语句曾经以 开头或结尾mov
,那通常表明您做错了。
关于asmSymbolicNames
,以下是 GCC Extended ASM HowTo对它们的评价:
此代码没有使用可选的 asmSymbolicName。因此它将第一个输出操作数引用为 %0(如果有第二个,它将是 %1 等)。第一个输入操作数的编号比最后一个输出操作数的编号大一个。在这个 i386 示例中,这使得 Mask 被引用为 %1:
uint32_t Mask = 1234; uint32_t Index; asm ("bsfl %1, %0" : "=r" (Index) : "r" (Mask) : "cc");
该代码覆盖变量索引 ('='),将值放入寄存器 ('r')。使用通用 'r' 约束而不是特定寄存器的约束允许编译器选择要使用的寄存器,这可以产生更高效的代码。如果汇编指令需要特定的寄存器,这可能是不可能的。
以下 i386 示例使用 asmSymbolicName 语法。它产生与上面的代码相同的结果,但有些人可能认为它更具可读性或更易于维护,因为在添加或删除操作数时不需要重新排序索引号。名称 aIndex 和 aMask 仅在此示例中用于强调在何处使用哪些名称。重复使用名称 Index 和 Mask 是可以接受的。
uint32_t Mask = 1234; uint32_t Index; asm ("bsfl %[aMask], %[aIndex]" : [aIndex] "=r" (Index) : [aMask] "r" (Mask) : "cc");
示例代码是内联汇编代码的一部分,可以使用 cl.exe 编译器在 win10 上成功编译...
回到 10,000 英尺,如果您正在寻找易于使用的东西来集成内联 ASM,例如在 Microsoft 环境中,那么您在 Linux 上没有它。GCC 内联 ASM 绝对烂。GCC 内联汇编器是一个古老的、难以使用的工具,我鄙视与之交互。
(而且您还没有经历过带有虚假线路信息的难以理解的错误消息)。
推荐阅读
- arrays - 用第二个数字从 curl 中提取数据
- javascript - 在 ng-template 中查看绑定到 ng-select 的子项不起作用
- php - 将旧应用程序 Laravel 4.2 中的 hasMany 关系更改为数组中的数据
- python - 将信号移至更高的频率范围
- javascript - 如何在项目复选框中包含 javascript,以便所选框自动计算价格值?
- reactjs - 将组件作为函数调用而不是将其用作标记时,React 没有相同的执行顺序?
- javascript - Node JS 部分视频流到 safari
- flutter - 使用颤振扫描二维码的问题
- flutter - Flutter:如何从孩子更新父母
- javascript - 如何使用 chrome background.js 继续计时器倒计时