需要弄清楚以下内联汇编代码的含义

时间:2013-02-17 14:19:10

标签: c assembly x86 inline-assembly

static int func_name (const uint8_t * address)
{
    int result;
    asm ("movl $1f, %0; movzbl %1, %0; 1:"
   : "=&a" (result) : "m" (*address));

    return result;
}

我通过互联网浏览了内联汇编。 但我无法弄清楚这段代码在做什么,例如。什么是$ 1f? “m”是什么意思?使用“= r”和“r”不是正常的内联约定吗?

3 个答案:

答案 0 :(得分:3)

$1f1标签的地址。 f指定在正向查找名为1的第一个标签。 "m"是内存中的输入操作数。 "=&a"是使用eax寄存器的输出操作数。 a指定要使用的寄存器,=使其成为输出操作数,&保证其他操作数不共享同一寄存器。

此处,%0将被第一个操作数(eax寄存器)和%1替换为第二个操作数(address指向的地址)。< / p>

Inline assemblyasm contraints的GCC文档中解释了所有这些以及更多内容。

答案 1 :(得分:2)

这段代码(除了由于两个拼写错误而无法编译)几乎没用。

这就是它(使用-S开关):

_func_name:
        movl 4(%esp), %edx ; edx = the "address" parameter
        movl $1f, %eax ; eax = the address of the "1" label
        movzbl (%edx), %eax; eax = byte from address in edx, IOW, "*address"
     1:
        ret

因此可以用

替换整个函数体
return *address;

答案 2 :(得分:2)

代码在功能上与return *address相同,但并不完全等同于此wrt。到生成的二进制/目标文件。

在ELF中,使用转发引用(即mov $1f, ...来检索程序集本地标签的地址)会导致创建所谓的重定位< / em>的。重定位是指向链接器(在可执行文件创建时或稍后在可执行文件/库加载时的动态链接器)到插入仅在链接/加载时已知的值的指令。在目标代码中,这看起来像:

Disassembly of section .text:

0000000000000000 :
   0:   b8 00 00 00 00          mov    $0x0,%eax
   5:   0f b6 07                movzbl (%rdi),%eax
   8:   c3                      retq

注意值(在.text部分的偏移量1处)在这里为零,即使实际上不正确 - 它取决于函数最终运行代码的位置。只有(动态)链接器才能最终知道这一点,并且这块内存在加载时需要更新的信息实际上放在了目标文件中:

$ readelf -a xqf.o
ELF Header:
[ ... ]
Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000000000  00000040
       0000000000000009  0000000000000000  AX       0     0     16
  [ 2] .rela.text        RELA             0000000000000000  000004e0
       0000000000000018  0000000000000018          10     1     8
[ ... ]
Relocation section '.rela.text' at offset 0x4e0 contains 1 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000000001  00020000000a R_X86_64_32       0000000000000000 .text + 8
[ ... ]

此ELF部分条目说:

  • 查看偏移1.text部分
  • 有一个32位的值会被符号扩展为64位(R_X86_64_32
  • 您(作为链接器)需要放置的值是.text + 8的值(必须在链接/加载时计算)

此条目由mov $1f, %0指令创建。如果你把它遗漏(或只是写return *address),它就不会存在。

我通过删除static限定符来强制执行上述代码生成;如果不这样做,一个简单的编译实际上会创建根本没有代码(如果不使用,static代码会被删除,并且,很多时候,如果使用内联,则会被内联)。

由于函数是static,如上所述,它通常由编译器在调用站点内联。因此,使用它的信息通常会丢失,调试器检测它的能力也会丢失。但是这里显示的技巧可以(间接)恢复,因为每次使用该函数都会创建一个重定位条目。除此之外,这样的方法可用于在二进制文件中建立检测点;在可通过目标文件格式恢复的位置插入众所周知/严格定义但功能无意义的小型汇编语句,然后例如调试器/跟踪实用程序在需要时用“更有用”的东西替换它们。