使用内联汇编读取变量
Reading variable with inline assembly
我想知道,根据实际指令读取输入变量是否有限制?
我正在尝试读取内联汇编中的输入变量,以便 .rept
指令重复一条指令 x
次。
但是,汇编程序抱怨:
Error: negative count for REPT - ignored
这是我的方法:
const int x = 42;
__asm__ volatile (".rept %[in]" :: [in] "m" (x));
__asm__ volatile (".endr");
尝试将变量值加载到寄存器中时如预期的那样工作:
int function(void) {
const int x = 42;
__asm__ volatile ("mov %[in], %%eax" :: [in] "m" (x));
__asm__ volatile ("ret");
}
returns 42
,反汇编符合预期。
我试着在汇编中写这个,看看常量是否可以与 .rept
指令一起使用,它确实如此
global _start
section .data
nvalue equ 39
section .text
_start:
push rbp
mov rbp, rsp
%rep nvalue
nop
%endrep
mov rax, 60
mov rdi, nvalue
syscall
反汇编符合预期:
Disassembly of section .text:
0000000000401000 <_start>:
401000: 55 push rbp
401001: 48 89 e5 mov rbp,rsp
401004: 90 nop
...
40102d: 90 nop
40102e: b8 3c 00 00 00 mov eax,0x3c
401033: bf 2a 00 00 00 mov edi,0x2a
401038: 0f 05 syscall
我是不是把 .rept
和 %rep
弄混了,它们不代表相同的操作吗?
任何帮助将不胜感激。
如评论中所述,i
操作数通常会插入前导 $
符号,这在 AT&T 语法中作为立即操作数是正确的,但不适合像 .rept
。您可以使用 c
修饰符来抑制它,请参阅 Section 6.47.2.8 of the GCC manual:
void many_nops(void) {
const int num = 42;
asm(".rept %c0 ; nop ; .endr" : : "i" (num));
}
这将内联 42 nop
条指令。当然,这只有在 num
可以折叠为编译时常量的情况下才有效;特别是你必须优化编译才能工作。
您还可以将 Intel asm 语法与 -masm=intel
结合使用,其中常量首先不会获得前导 $
。
请注意,您的内联 asm 存在许多其他问题(您不能从内联 asm ret
,不应该在多个 asm
语句之间拆分代码,等等)所以您可能想先阅读 https://whosebug.com/tags/inline-assembly/info.
上的一些常见问题解答
.rept
与 %rep
的问题:第一个是 GNU 汇编程序 gas
的正确语法,通常用于汇编 GCC 输出,第二个是nasm
汇编程序。
我想知道,根据实际指令读取输入变量是否有限制?
我正在尝试读取内联汇编中的输入变量,以便 .rept
指令重复一条指令 x
次。
但是,汇编程序抱怨:
Error: negative count for REPT - ignored
这是我的方法:
const int x = 42;
__asm__ volatile (".rept %[in]" :: [in] "m" (x));
__asm__ volatile (".endr");
尝试将变量值加载到寄存器中时如预期的那样工作:
int function(void) {
const int x = 42;
__asm__ volatile ("mov %[in], %%eax" :: [in] "m" (x));
__asm__ volatile ("ret");
}
returns 42
,反汇编符合预期。
我试着在汇编中写这个,看看常量是否可以与 .rept
指令一起使用,它确实如此
global _start
section .data
nvalue equ 39
section .text
_start:
push rbp
mov rbp, rsp
%rep nvalue
nop
%endrep
mov rax, 60
mov rdi, nvalue
syscall
反汇编符合预期:
Disassembly of section .text:
0000000000401000 <_start>:
401000: 55 push rbp
401001: 48 89 e5 mov rbp,rsp
401004: 90 nop
...
40102d: 90 nop
40102e: b8 3c 00 00 00 mov eax,0x3c
401033: bf 2a 00 00 00 mov edi,0x2a
401038: 0f 05 syscall
我是不是把 .rept
和 %rep
弄混了,它们不代表相同的操作吗?
任何帮助将不胜感激。
如评论中所述,i
操作数通常会插入前导 $
符号,这在 AT&T 语法中作为立即操作数是正确的,但不适合像 .rept
。您可以使用 c
修饰符来抑制它,请参阅 Section 6.47.2.8 of the GCC manual:
void many_nops(void) {
const int num = 42;
asm(".rept %c0 ; nop ; .endr" : : "i" (num));
}
这将内联 42 nop
条指令。当然,这只有在 num
可以折叠为编译时常量的情况下才有效;特别是你必须优化编译才能工作。
您还可以将 Intel asm 语法与 -masm=intel
结合使用,其中常量首先不会获得前导 $
。
请注意,您的内联 asm 存在许多其他问题(您不能从内联 asm ret
,不应该在多个 asm
语句之间拆分代码,等等)所以您可能想先阅读 https://whosebug.com/tags/inline-assembly/info.
.rept
与 %rep
的问题:第一个是 GNU 汇编程序 gas
的正确语法,通常用于汇编 GCC 输出,第二个是nasm
汇编程序。