GCC将汇编引脚局部变量扩展到除r12以外的任何寄存器

GCC将汇编引脚局部变量扩展到除r12以外的任何寄存器,c,gcc,x86,inline-assembly,C,Gcc,X86,Inline Assembly,基本上,我正在寻找一种方法,将临时寄存器固定到除r12之外的任何寄存器 我知道我可以通过以下方式“提示”编译器将其固定到单个寄存器: // Toy example. Obviously an unbalanced `pop` in // extended assembly will cause serious problems. register long tmp asm("rdi"); // or just clober rdi and use it directly.

基本上,我正在寻找一种方法,将临时寄存器固定到除
r12
之外的任何寄存器

我知道我可以通过以下方式“提示”编译器将其固定到单个寄存器:

// Toy example. Obviously an unbalanced `pop` in 
// extended assembly will cause serious problems.

register long tmp asm("rdi"); // or just clober rdi and use it directly.
asm volatile("pop %[tmp]\n"   // using pop hence don't want r12
             : [tmp] "=&r" (tmp)
             :
             :);
这通常与避免r12一样有效,但可能会扰乱编译器在其他地方的寄存器分配


是否可以在不强制编译器使用单个寄存器的情况下执行此操作?

请注意,
寄存器asm
不会真正将变量“固定”到寄存器,它只确保在内联asm中将该变量用作操作数时使用该寄存器。原则上,变量可以存储在两者之间的其他位置。看见但听起来您真正需要的是确保
pop
指令不使用
r12
作为其操作数,这可能是因为。我不知道有什么方法可以做到这一点,但这里有一些可能会有所帮助的选择

寄存器
rax、rbx、rcx、rdx、rsi、rdi
各自有各自的约束字母,
a、b、c、d、S、d
(其他寄存器没有)。所以你可以通过做一些事情来达到一半

long tmp;
asm volatile("pop %[tmp]\n"
             : [tmp] "=&abcdSD" (tmp)
             :
             :);
通过这种方式,编译器可以选择这六个寄存器中的任意一个,这将为寄存器分配器提供更大的灵活性

另一个选项是声明asm缓冲区
r12
,这将阻止编译器在那里分配操作数:

long tmp;
asm volatile("pop %[tmp]\n"
             : [tmp] "=&r" (tmp)
             :
             : "r12");
折衷的办法是,它也不会使用
r12
asm
中缓存局部变量,因为它假定可以修改它。希望它足够聪明,完全避免在代码的这一部分使用
r12
,但如果不能,它可能会发出额外的寄存器移动或溢出到asm周围的堆栈中。不过,它没有
-ffix-r12
那么残酷,这将阻止编译器在整个源文件的任何位置使用
r12



未来的读者应该注意,在x86-64上修改内联asm中的堆栈指针通常是不安全的。编译器假定内联asm不会更改
rsp
,它可以通过有效地址访问堆栈变量,该地址具有相对于
rsp
的恒定偏移量。此外,x86-64使用了一个,因此即使是
push/pop
对也不安全,因为可能有重要数据存储在
rsp
下面。(意外的
pop
可能意味着其他重要数据不再位于红色区域,因此可能会被信号处理程序覆盖。)因此,您不应该这样做,除非您愿意在每次重新编译后仔细阅读生成的程序集,以确保编译器没有决定执行这些操作。(在您询问之前,您不能通过声明一个
rsp的clobber来解决这个问题;这是不受支持的。)

注意
寄存器asm
并不是真正将变量“固定”到寄存器,它只确保在内联asm中将该变量用作操作数时使用该寄存器。原则上,变量可以存储在两者之间的其他位置。看见但听起来您真正需要的是确保
pop
指令不使用
r12
作为其操作数,这可能是因为。我不知道有什么方法可以做到这一点,但这里有一些可能会有所帮助的选择

寄存器
rax、rbx、rcx、rdx、rsi、rdi
各自有各自的约束字母,
a、b、c、d、S、d
(其他寄存器没有)。所以你可以通过做一些事情来达到一半

long tmp;
asm volatile("pop %[tmp]\n"
             : [tmp] "=&abcdSD" (tmp)
             :
             :);
通过这种方式,编译器可以选择这六个寄存器中的任意一个,这将为寄存器分配器提供更大的灵活性

另一个选项是声明asm缓冲区
r12
,这将阻止编译器在那里分配操作数:

long tmp;
asm volatile("pop %[tmp]\n"
             : [tmp] "=&r" (tmp)
             :
             : "r12");
折衷的办法是,它也不会使用
r12
asm
中缓存局部变量,因为它假定可以修改它。希望它足够聪明,完全避免在代码的这一部分使用
r12
,但如果不能,它可能会发出额外的寄存器移动或溢出到asm周围的堆栈中。不过,它没有
-ffix-r12
那么残酷,这将阻止编译器在整个源文件的任何位置使用
r12



未来的读者应该注意,在x86-64上修改内联asm中的堆栈指针通常是不安全的。编译器假定内联asm不会更改
rsp
,它可以通过有效地址访问堆栈变量,该地址具有相对于
rsp
的恒定偏移量。此外,x86-64使用了一个,因此即使是
push/pop
对也不安全,因为可能有重要数据存储在
rsp
下面。(意外的
pop
可能意味着其他重要数据不再位于红色区域,因此可能会被信号处理程序覆盖。)因此,您不应该这样做,除非您愿意在每次重新编译后仔细阅读生成的程序集,以确保编译器没有决定执行这些操作。(在你提问之前,你不能通过声明一个
rsp的clobber来解决这个问题;这是不受支持的。)

你的
asm
只是一个例子,还是你真正想要的?在内联asm中弹出堆栈将彻底破坏生成的代码。哦,你是否因为以下原因而试图避免r12?这只是一个例子。试图制作一个小片段,在紧密循环中禁用LSD。实际上,将在循环前保存,并在pop后使用
movq
进行恢复。即
#定义无LSD(tmp,r)“pop”#tmp”\nmovq”#r“,%%rsp\n”
#定义无LSD(tmp,r)“push”#tmp”\nmovq”#r“,%%rsp\n
其中
tmp
不需要
r12
,一个部分解决方案是使用ABSD代码作为约束条件