为什么不能在GNU C基本内联asm语句中使用局部变量? [英] Why can't local variable be used in GNU C basic inline asm statements?

查看:184
本文介绍了为什么不能在GNU C基本内联asm语句中使用局部变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么不能使用main中的局部变量在基本asm内联中使用?只能在扩展的asm中使用,但为什么要这样做?

Why cannot I use local variables from main to be used in basic asm inline? It is only allowed in extended asm, but why so?

(我知道局部变量位于返回地址之后的堆栈中(因此一旦函数返回就无法使用),但这不应该成为不使用它们的原因)

(I know local variables are on the stack after return address (and therefore cannot be used once the function return), but that should not be the reason to not use them)

基本asm示例:

int a = 10; //global a
int b = 20; //global b
int result;
int main()
{
 asm ( "pusha\n\t"
 "movl a, %eax\n\t"
 "movl b, %ebx\n\t"
 "imull %ebx, %eax\n\t"
 "movl %eax, result\n\t"
 "popa");
printf("the answer is %d\n", result);
return 0;
}

扩展示例:

int main (void) {

    int data1 = 10;  //local var - could be used in extended
    int data2 = 20;
    int result;

    asm ("imull %%edx, %%ecx\n\t"
          "movl %%ecx, %%eax" 
          : "=a"(result)
          : "d"(data1), "c"(data2));

    printf("The result is %d\n",result);

    return 0;
}

编译: gcc -m32 somefile.c

平台: uname -a: Linux 5.0.0-32-generic #34-Ubuntu SMP Wed Oct 2 02:06:48 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

推荐答案

基本asm"和扩展asm"之间几乎没有区别; 基本汇编"只是一个特殊情况,其中__asm__语句没有输出,输入或修饰符的列表.编译器不会在Basic asm的汇编字符串中执行%替换.如果需要输入或输出,则必须指定它们,这就是人们所说的扩展的asm".

There is little distinction between "Basic asm" and "Extended asm"; "basic asm" is just a special case where the __asm__ statement has no lists of outputs, inputs, or clobbers. The compiler does not do % substitution in the assembly string for Basic asm. If you want inputs or outputs you have to specify them, and then it's what people call "extended asm".

实际上,可以从基本asm"访问外部(甚至文件范围的静态)对象.这是因为这些对象将(分别可能)在程序集级别具有符号名称.但是,要执行这样的访问,您需要注意它是否与位置无关(如果您的代码将被链接到库或PIE可执行文件中)并且满足在链接时可能施加的其他ABI约束,并且有很多注意事项与链接时优化和编译器可能执行的其他转换的兼容性.简而言之,这是一个坏主意,因为您无法告诉编译器基本的asm语句已修改内存.没有办法使它安全.

In practice, it may be possible to access external (or even file-scope static) objects from "basic asm". This is because these objects will (respectively may) have symbol names at the assembly level. However, to perform such access you need to be careful of whether it is position-independent (if your code will be linked into libraries or PIE executables) and meets other ABI constraints that might be imposed at linking time, and there are various considerations for compatibility with link-time optimization and other transformations the compiler may perform. In short, it's a bad idea because you can't tell the compiler that a basic asm statement modified memory. There's no way to make it safe.

"memory" Clobber(扩展的asm)可以使从asm模板中按名称访问静态存储变量变得安全.

A "memory" clobber (Extended asm) can make it safe to access static-storage variables by name from the asm template.

基本asm的用例是仅修改机器状态的事物,例如内核中的asm("cli")以禁用中断,而无需读取或写入任何C变量. (即使那样,您也经常使用内存"缓冲区来确保编译器在更改计算机状态之前已经完成了较早的内存操作.)

The use-case for basic asm is things that modify the machine state only, like asm("cli") in a kernel to disable interrupts, without reading or writing any C variables. (Even then, you'd often use a "memory" clobber to make sure the compiler had finished earlier memory operations before changing machine state.)

局部变量(自动存储,不是静态变量)从根本上没有符号名称,因为它们不存在于单个实例中.在运行时,在其中声明的块的每个活动实例中都有一个对象.因此,访问它们的唯一可能方法是通过输入/输出约束.

Local (automatic storage, not static ones) variables fundamentally never have symbol names, because they don't exist in a single instance; there's one object per live instance of the block they're declared in, at runtime. As such, the only possible way to access them is via input/output constraints.

来自MSVC领域的用户可能会感到惊讶,因为MSVC的内联汇编方案通过将内联asm版本中的局部变量引用转换为相对于堆栈指针的访问来解决了该问题.但是,它提供的内联汇编版本与优化编译器不兼容,并且使用该类内联汇编的函数几乎没有优化可以进行. GCC和与Unix一起与C一起成长的更大的编译器世界没有任何相似之处.

Users coming from MSVC-land may find this surprising since MSVC's inline assembly scheme papers over the issue by transforming local variable references in their version of inline asm into stack-pointer-relative accesses, among other things. The version of inline asm it offers however is not compatible with an optimizing compiler, and little to no optimization can happen in functions using that type of inline asm. GCC and the larger compiler world that grew alongside C out of unix does not do anything similar.

这篇关于为什么不能在GNU C基本内联asm语句中使用局部变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆