2011-08-21 110 views
5

我想了解一些关于Linux内联汇编器的内容。我使用下面的函数:ASM内联怀疑

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的内存地址到EAX寄存器的值,而不是VAR值。

有没有什么办法告诉addl指令使用var值而不是将var mem地址复制到寄存器?

Regards

+0

你的内联汇编没有定义什么是应该是在EAX,所以GCC可以把任何那里...你居然想干什么? – servn

回答

3

它将var mem地址与eax寄存器值相加var值。

是的,gcc内联汇编的语法非常神秘。来自GCC Inline Assembly HOWTO"m"中的相关部分的释义粗略地给出了C变量的内存位置。

这就是你想要的地址,你可以写或读的地方。注意我说的是变量的位置,所以%0设置为Word32 *var的地址 - 你有一个指向指针的指针。内联汇编块的C语言翻译看起来像EAX += *(&var),因为您可以说"m"约束隐含地使用C变量的地址,并为您提供地址表达式,然后将其添加到%eax

有没有什么办法告诉addl指令使用var值而不是将var mem地址复制到寄存器?

这取决于你的意思。你需要从堆栈中得到var,所以有人提领内存(请参阅@Bo Perssons答案),但你没有做内联汇编

约束必须"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 list上的章节,并特别注意"memory" clobber的高级使用内联汇编。

即使你不想(明确地)将内存地址加载到寄存器中,我会简要地介绍它。 从"m"更改约束"r"几乎似乎工作,有关章节得到改变到(如果包括在撞列表%eax):

movl 8(%ebp), %edx 
    addl %edx, %eax 

这几乎是正确的,我们已经加载的指针值var成一个注册表,但现在我们必须指定我们正在从内存加载。改变代码相匹配的约束(通常不希望的,我只显示它的完整性):

asm("addl (%0), %%eax" : : "r"(var) : "%eax"); 

给出:

movl 8(%ebp), %edx 
addl (%edx), %eax 

同样作为与"m"

3

是的,因为你给他var是地址。给他* var。

喜欢:

void test_func(Word32 *var){ 
    asm(" addl %0, %%eax" : : "m"(*var)); 
    return; 
} 

我不记得确切,但你应该取代 “M” 和 “R”?

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

+0

这样做会覆盖%var eax值以获取var值。 – LooPer

1

不,对于x86处理器来说,没有寻址模式间接使用两级。

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

0

尝试

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

    return; 
}