c - GNU C 内联 asm "m"约束与指针 : address vs. 指向的值?

标签 c assembly gcc inline-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" 1
        addl 8(%ebp), %eax
# 0 "" 2
#NO_APP
        popl %ebp
        ret
        .size   test_func, .-test_func

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

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

问候

最佳答案

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

是的,gcc 内联汇编的语法非常晦涩难懂。摘自 GCC Inline Assembly HOWTO 中的相关部分"m"粗略地给出 C 变量的内存位置。

当您只需要一个可以写入或读取的地址时,您可以使用它。请注意,我说的是 C 变量的位置,因此 %0设置为地址Word32 *var - 你有一个指向指针的指针。内联汇编 block 的 C 语言翻译可能类似于 EAX += *(&var)因为你可以说 "m"约束隐式获取 C 变量的地址并为您提供一个地址表达式,然后将其添加到 %eax

有没有办法告诉addl指令使用var值而不是var mem地址而不将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" 相同.

关于c - GNU C 内联 asm "m"约束与指针 : address vs. 指向的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7139305/

相关文章:

c - 发送到() : Bad file descriptor in UDP - IPv6

linux - x86_64 机器的 GCC 内联汇编的汇编程序错误(at&t 语法)

macos - os x 中的汇编语言

c - Windows 操作系统中 Code::Blocks 编辑器中对 fork() 的 undefined reference

c - 为什么使用线程的程序会花费更多的时间?

c - Swift/C 互操作,Swift 中的结构数据更改未在 C 中更新

C TUI 开发 - 帮助/教程?

assembly - 内存地址和偏移量

linux - 当设置为按引用返回时,Linux 中的 Firebird UDF 会导致服务器崩溃

c - 简单的C语言解析器不编译linux机器