昨天我了解到,在编译AMD64和Itanium目标时,Microsoft Visual C++不支持内联汇编(使用__asm关键字).
那是对的吗?如果是这样,有谁知道为什么他们不支持这些目标的内联汇编?这似乎是一个相当大的特点,只是放弃......
是否可以在C中访问32位寄存器?如果是的话,怎么样?如果没有,那么有没有办法在C中嵌入汇编代码?顺便说一下,我正在使用MinGW编译器.提前致谢!
如果要从内联汇编中调用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.
我正在尝试使用GCC的内联汇编程序熟悉x86程序集.我正在尝试添加两个数字(a和b)并存储结果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) 我正在尝试使用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位内存寻址.
pusha- > push %ax; push %cx; push %dx; push %bx; push %sp; push %bp; push …
在C程序中使用汇编语言的目的是什么?编译器已经能够生成汇编语言.在什么情况下编写汇编比C更好?性能是否考虑?
我正在编写实模式函数,它应该是具有堆栈帧的正常函数,但是它应该使用%sp而不是%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) 假设我有一些内联汇编,需要一个特定char的值ah,bh,ch,或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(是否带a,Q或r),然后我得到了想要的结果:
movb 4(%esp), %ah
# my value ended up in %ah
Run Code Online (Sandbox Code Playgroud)
我还尝试使用bh、 …
以下摘自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 汇编,因此请让示例针对该平台。