Gcc 无疑问

Gcc 无疑问,gcc,assembly,Gcc,Assembly,我试图了解Linux中内联汇编程序的一些内容。我正在使用以下功能: void test_func(Word32 *var){ asm( " addl %0, %%eax" : : "m"(var) ); return; } 它生成以下汇编代码: .globl test_func .type test_func, @function test_func: pushl %ebp movl %esp, %ebp #APP # 336 "opers.c"

我试图了解Linux中内联汇编程序的一些内容。我正在使用以下功能:

void test_func(Word32 *var){
   asm( " addl %0, %%eax" : : "m"(var) );
   return;
}
它生成以下汇编代码:

.globl test_func
.type   test_func, @function
test_func:
        pushl %ebp
        movl %esp, %ebp
#APP
# 336 "opers.c" 1
        addl 8(%ebp), %eax
# 0 "" 2
#NO_APP
        popl %ebp
        ret
        .size   test_func, .-test_func
它将var mem地址和eax寄存器值相加,而不是var值

有没有办法告诉addl指令在不将var mem地址复制到寄存器的情况下使用var value而不是var mem address


问候

是的,因为你给了他一个var,即地址。给他

比如:

我记不清了,但你应该把“m”换成“r”


内存操作数不存在;这并不意味着它将从该地址获取价值。它只是一个指针

不,x86处理器没有两级间接寻址模式


您必须首先从内存地址加载指针,然后从指针间接加载。

它将var mem地址和eax寄存器值相加,而不是var值。

是的,gcc内联程序集的语法相当神秘。从
“m”
中的相关部分进行解释,大致给出C变量的内存位置

当你只需要一个可以写或读的地址时,你会使用它。注意我说的是C变量的位置,所以
%0
被设置为
Word32*var
的地址-您有一个指向指针的指针。内联程序集块的C转换可能看起来像
EAX+=*(&var)
,因为您可以说
“m”
约束隐式获取C变量的地址,并为您提供一个地址表达式,然后将其添加到
%EAX

有没有办法告诉addl指令使用var value而不是var mem address,而不将var mem address复制到寄存器中?

那要看你的意思了。您需要从堆栈中获取
var
,因此必须有人取消对内存的引用(请参见@Bo Perssons answer),但您不必在内联汇编中执行此操作

约束必须是
“m”(*var)
(正如@fazo建议的那样)。这将为您提供
var
所指向的值的内存位置,而不是指向它的内存位置

生成的代码现在是:

test_func:
    pushl   %ebp
    movl    %esp, %ebp
    movl    8(%ebp), %eax
#APP
# 2 "test.c" 1
    addl    (%eax), %eax
# 0 "" 2
#NO_APP
    popl    %ebp
    ret
这有点可疑,但这是可以理解的,因为您忘了告诉GCC您已经失败(在输入/输出列表中没有修改)
%eax
。修复
asm(“addl%0,%%eax):“m”(*var):%eax”)
生成:

    movl    8(%ebp), %edx
    addl    (%edx), %eax
在这种情况下,这并不是更好或更正确,但记住它始终是一个很好的做法。请参阅上的部分,并特别注意
“内存”
clobber,以了解内联程序集的高级用法

即使您不想(显式地)将内存地址加载到寄存器中,我也将简要介绍一下。 将约束从
“m”
更改为
“r”
似乎几乎可行,相关部分将更改为(如果我们将
%eax
包括在clobber列表中):

这几乎是正确的,我们已经将指针值
var
加载到一个寄存器中,但是现在我们必须指定从内存加载的指针值。更改代码以匹配约束(通常不受欢迎,我只是为了完整性而展示):

给出:

movl    8(%ebp), %edx
addl    (%edx), %eax
“m”相同

试试看

void test_func(Word32 *var){
    asm( " mov %0, %%edx; \
    addl (%%edx), %%eax" : : "m"(var) );    

    return;
} 

这样做将用var地址覆盖%eax值以获取var值。您的内联asm没有定义eax中应该包含的内容,因此gcc可以将任何内容放在那里。。。你到底想做什么?
asm("addl (%0), %%eax" : : "r"(var) : "%eax" );
movl    8(%ebp), %edx
addl    (%edx), %eax
void test_func(Word32 *var){
    asm( " mov %0, %%edx; \
    addl (%%edx), %%eax" : : "m"(var) );    

    return;
}