标签: inline-assembly

为什么MSVC不支持AMD64和Itanium目标的内联汇编?

昨天我了解到,在编译AMD64和Itanium目标时,Microsoft Visual C++不支持内联汇编(使用__asm关键字).

那是对的吗?如果是这样,有谁知道为什么他们不支持这些目标的内联汇编?这似乎是一个相当大的特点,只是放弃......

assembly x86-64 itanium inline-assembly visual-c++

11
推荐指数
2
解决办法
4360
查看次数

是否可以在C中访问32位寄存器?

是否可以在C中访问32位寄存器?如果是的话,怎么样?如果没有,那么有没有办法在C中嵌入汇编代码?顺便说一下,我正在使用MinGW编译器.提前致谢!

c assembly mingw inline-assembly cpu-registers

11
推荐指数
2
解决办法
2万
查看次数

使用GCC的内联汇编直接调用

如果要从内联汇编中调用C/C++函数,可以执行以下操作:

void callee() {}
void caller()
{
    asm("call *%0" : : "r"(callee));
}
Run Code Online (Sandbox Code Playgroud)

然后GCC将发出如下所示的代码:

movl $callee, %eax
call *%eax
Run Code Online (Sandbox Code Playgroud)

这可能会有问题,因为间接调用会破坏旧CPU上的管道.

由于地址callee最终是常量,可以想象可以使用i约束.引自GCC在线文档:

'我"

允许使用立即整数操作数(具有常量值的操作数).这包括符号常量,其值仅在汇编时或以后知道.

如果我尝试这样使用它:

asm("call %0" : : "i"(callee));
Run Code Online (Sandbox Code Playgroud)

我从汇编程序中收到以下错误:

错误:后缀或操作数对`call'无效

这是因为GCC会发出代码

call $callee
Run Code Online (Sandbox Code Playgroud)

代替

call callee
Run Code Online (Sandbox Code Playgroud)

所以我的问题是是否可以使GCC输出正确call.

c c++ gcc inline-assembly function-call

11
推荐指数
1
解决办法
9852
查看次数

添加两个数字

我正在尝试使用GCC的内联汇编程序熟悉x86程序集.我正在尝试添加两个数字(ab)并存储结果c.我有四个略有不同的尝试,其中三个有效; 最后一个不会产生预期的结果.

前两个示例使用中间寄存器,这些都可以正常工作.第三个和第四个示例尝试直接添加两个值而不使用中间寄存器,但结果会根据优化级别和添加输入值的顺序而有所不同.我错了什么?

环境是:

i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3)
Run Code Online (Sandbox Code Playgroud)

首先,变量声明如下:

int a = 4;
int b = 7;
int c;
Run Code Online (Sandbox Code Playgroud)

例1:

asm("   movl    %1,%%eax;"
    "   addl    %2,%%eax;"
    "   movl    %%eax,%0;"
    : "=r" (c)
    : "r" (a), "r" (b)
    : "%eax"
   );
printf("a=%d, b=%d, c=%d\n", a, b, c);
// output: a=4, b=7, c=11
Run Code Online (Sandbox Code Playgroud)

例2:

asm("   movl    %2,%%eax;"
    "   addl    %1,%%eax;"
    "   movl    %%eax,%0;"
    : "=r" (c)
    : "r" (a), "r" (b) …
Run Code Online (Sandbox Code Playgroud)

x86 gcc inline-assembly

11
推荐指数
1
解决办法
2688
查看次数

如何将Linux 32位gcc内联汇编转换为64位代码?

我正在尝试使用gcc在Linux 中将RR0D Rasta Ring 0调试器从32位模式转换为64位模式(长模式).我熟悉x86 32位程序集(在MS-DOS环境中),但我是x86 64位程序集和Linux程序集编程的初学者.

这个项目是供生产使用的(我需要一个可用的非源调试器),但我也尝试学习如何进行32位到64位的转换.如果可能的话,我试图找到一种通用的方法来进行32位到64位的转换,可以使用正则表达式在任何32位程序上完成(这样它就可以自动化).我知道没有通用的解决方案(64位代码可能占用比32位代码更多的空间等,并且消耗更多的堆栈等),但即使在这种情况下,自动转换的代码也可以作为起点.

我们的想法是保持8位和16位操作数不变,并用64位操作数替换32位操作数.如果pushw %ax; pushw %bx; popl %ecx替换为这种方法自然会失败pushw %ax; pushw %bx; popq %rcx,但是性能良好的程序通常不会有push两个16位操作数,而是pop一个32位操作数,或者它们呢?

这些是到目前为止的转换:

编辑:修复:pusha/ pushad 可以用连续的push'es 替换,因为pusha/ pushad命令在实际推送之前推送sp/ 的值,并且在286+中以相同的方式工作,但在8088/8086 汇编语言数据库中有所不同.这种差异不是问题(对于386+代码).并且因此可以与连续的替换命令.esp sppush sppushapushadpush

替代方法与OpenSolaris的privregs.h代码类似.

编辑:修复:对所有命令使用64位内存寻址.

  1. pusha- > push %ax; push %cx; push %dx; push %bx; push %sp; push %bp; push …

linux assembly gcc x86-64 inline-assembly

11
推荐指数
0
解决办法
2770
查看次数

在C程序中使用汇编语言的目的是什么?

在C程序中使用汇编语言的目的是什么?编译器已经能够生成汇编语言.在什么情况下编写汇编比C更好?性能是否考虑?

c assembly inline-assembly

11
推荐指数
3
解决办法
2098
查看次数

如何告诉GCC为实模式生成16位代码

我正在编写实模式函数,它应该是具有堆栈帧的正常函数,但是它应该使用%sp而不是%esp.有办法吗?

c assembly gcc inline-assembly x86-16

11
推荐指数
4
解决办法
9011
查看次数

GCC/x86内联asm:你怎么告诉gcc内联汇编部分会修改%esp?

在试图让一些旧代码再次运行时(https://github.com/chaos4ever/chaos/blob/master/libraries/system/system_calls.h#L387,FWIW)我发现一些语义gcc似乎已经改变了在最近10到15年间,以一种非常微妙但仍然危险的方式......:P

该代码曾用于旧版本gcc,如2.95.无论如何,这是代码:

static inline return_type system_call_service_get(const char *protocol_name, service_parameter_type *service_parameter,
    tag_type *identification)
{
    return_type return_value;

    asm volatile("pushl %2\n"
                 "pushl %3\n"
                 "pushl %4\n"
                 "lcall %5, $0"
                 : "=a" (return_value),
                   "=g" (*service_parameter)
                 : "g" (identification),
                   "g" (service_parameter),
                   "g" (protocol_name),
                   "n" (SYSTEM_CALL_SERVICE_GET << 3));

    return return_value;
}
Run Code Online (Sandbox Code Playgroud)

上面的代码的问题是gcc(在我的情况下为4.7)将编译为以下asm代码(AT&T语法):

# 392 "../system/system_calls.h" 1
pushl 68(%esp)  # This pointer (%esp + 0x68) is valid when the inline asm is entered.
pushl %eax
pushl 48(%esp)  # ...but this …
Run Code Online (Sandbox Code Playgroud)

c x86 assembly gcc inline-assembly

11
推荐指数
1
解决办法
1096
查看次数

如何让 GCC 在 ah/bh/ch/dh 中放置一个字符?

假设我有一些内联汇编,需要一个特定char的值ahbhch,或dh。我怎么能告诉 GCC 把它放在那里?我没有看到相关的约束来做到这一点,但 GCC 手册说“如果你必须使用特定的寄存器,但你的机器约束没有提供足够的控制来选择你想要的特定寄存器,局部寄存器变量可能会提供一个解决方案",所以我试过:

void f(char x) {
    register char y __asm__("ah") = x;
    __asm__ __volatile__(
        "# my value ended up in %0" :: "a"(y)
    );
}
Run Code Online (Sandbox Code Playgroud)

但它没有用。它al改为:

        movb    4(%esp), %al
        # my value ended up in %al
Run Code Online (Sandbox Code Playgroud)

特定于 x86 的Q约束看起来也很接近我想要的,所以我尝试用它代替a,但结果相同。我还尝试使用更通用的r.

有趣的是,当我编译铿锵而不是GCC(是否带aQr),然后我得到了想要的结果:

        movb    4(%esp), %ah
        # my value ended up in %ah
Run Code Online (Sandbox Code Playgroud)

我还尝试使用bh、 …

c x86 assembly gcc inline-assembly

11
推荐指数
1
解决办法
161
查看次数

在 GCC 内联汇编中影响内存操作数寻址模式的早期破坏者的不正确行为的具体示例?

以下摘自GCC 手册的 Extended Asm docs,关于使用asm关键字在 C 中嵌入汇编指令:

如果一个输出参数 ( a ) 允许寄存器约束而另一个输出参数 ( b ) 允许内存约束,则会出现同样的问题。GCC 生成的用于访问b 中的内存地址的代码 可以包含可能由a共享的寄存器,并且 GCC 将这些寄存器视为 asm 的输入。如上所述,GCC 假设在写入任何输出之前消耗此类输入寄存器。如果 asm 语句在使用 b 之前写入 a,则此假设可能会导致不正确的行为。与对寄存器约束结合“&”改性剂确保修改一个不影响通过引用的地址b. 否则,位置b,如果未定义 一个使用之前改性b

斜体句子表示如果 asm 语句a在使用b.

我无法弄清楚这种“不正确的行为”是如何发生的,所以我希望有一个具体的 asm 代码示例来演示“不正确的行为”,以便我可以深入理解这一段。

当两个这样的 asm 代码并行运行时,我可以察觉到问题,但上面的段落没有提到多处理场景。

如果我们只有一个单核的CPU,能否请您出示一个asm代码,可能会产生这样的错误行为,即修改a影响引用的地址,b使得其位置b未定义。

我唯一熟悉的汇编语言是 Intel x86 汇编,因此请让示例针对该平台。

x86 assembly gcc register-allocation inline-assembly

11
推荐指数
2
解决办法
256
查看次数