如何让汇编程序给我一个完整的寄存器"?

时间:2015-01-11 20:50:34

标签: gcc assembly x86-64 inline-assembly

我正在尝试允许汇编程序给我一个它选择的寄存器,然后将该寄存器与内联汇编一起使用。我正在使用下面的程序,以及它的分段错误。该程序编译为g++ -O1 -g2 -m64 wipe.cpp -o wipe.exe

当我看到lldb下的崩溃时,我相信我得到的是32位寄存器而不是64位寄存器。我正在尝试使用lea计算地址(基数+偏移量),并将结果存储在汇编程序选择的寄存器中:

"lea (%0, %1), %2\n"

上面,我试图说“使用寄存器,我将其称为%2”。

当我执行反汇编时,我看到:

   0x100000b29:  leal   (%rbx,%rsi), %edi
-> 0x100000b2c:  movb   $0x0, (%edi)

因此,生成的代码似乎使用64位值(rbx和rsi)计算和地址,但将其保存到32位寄存器(edi)(汇编程序选择)。

以下是崩溃时的值:

(lldb) type format add --format hex register
(lldb) p $edi
(unsigned int) $3 = 1063330
(lldb) p $rbx
(unsigned long) $4 = 4296030616
(lldb) p $rsi
(unsigned long) $5 = 10

下面输入操作数的快速说明。如果我删除了"r" (2),那么当我在%2lea的调用中引用invalid operand number in inline asm string时出现编译错误。

如何告诉汇编程序“给我一个完整规格的寄存器”,然后在我的程序中参考它?


int main(int argc, char* argv[])
{
    string s("Hello world");
    cout << s << endl;

    char* ptr = &s[0];
    size_t size = s.length();

    if(ptr && size)
    {
        __asm__ __volatile__
        (
         "%=:\n"                /* generate a unique label for TOP */

         "subq $1, %1\n"        /* 0-based index */
         "lea (%0, %1), %2\n"   /* calcualte ptr[idx] */
         "movb $0, (%2)\n"      /* 0 -> ptr[size - 1] .. ptr[0] */
         "jnz %=b\n"            /* Back to TOP if non-zero */

         : /* no output */
         :  "r" (ptr), "r" (size), "r" (2)
         : "0", "1", "2", "cc"
         );
    }

    return 0;
}

对于这些内联汇编问题,我们深表歉意。我希望这是最后一个。我不是很高兴在GCC中使用内联汇编,因为这样的痛点(以及我的消失记忆)。但是,鉴于GCC对C中限定符volatile的解释,它是我所知道的唯一 合法 方式。

如果有兴趣,GCC会将C的volatile限定符解释为hardware backed memory,其他任何内容都是滥用行为,并导致非法程序。因此以下是GCC的 合法:

volatile void* g_tame_the_optimizer = NULL;
...

unsigned char* ptr = ...
size_t size = ...;

for(size_t i = 0; i < size; i++)
   ptr[i] = 0x00;

g_tame_the_optimizer = ptr;

有趣的是,微软使用volatile的更习惯的解释(大多数程序员都期望 - 即,任何东西都可以改变内存,而不仅仅是内存映射硬件),上面的代码是可以接受的。

1 个答案:

答案 0 :(得分:4)

gcc inline asm是一个复杂的野兽。 "r" (2)表示分配int大小的寄存器并使用值2加载它。如果你只需要一个任意的临时寄存器,你可以声明一个64位的早期clobber虚拟输出,例如输出部分中的"=&r" (dummy),前面已经声明了void *dummy。有关详细信息,请参阅gcc manual

至于最终的代码片段看起来像是一个内存障碍,就像链接的电子邮件所说的那样。请参阅manual for example