2017-01-27 9 views
3

Я все еще борюсь с встроенным ассемблером g ++ и пытаюсь понять, как его использовать.Попытка понять простой дизассемблированный код из g ++

Я приспособил кусок кода здесь: http://asm.sourceforge.net/articles/linasm.html (Цитируется из «Ассемблера инструкции с C Выражение Операндов» раздел в ССАГПЗЕ информационных файлов)

static inline uint32_t sum0() { 
    uint32_t foo = 1, bar=2; 
    uint32_t ret; 
    __asm__ __volatile__ (
     "add %%ebx,%%eax" 
     : "=eax"(ret)    // ouput 
     : "eax"(foo), "ebx"(bar) // input 
     : "eax"     // modify 
    ); 
    return ret; 
} 

Я составил инвалидизирующие оптимизации:

g++ -Og -O0 inline1.cpp -o test 

разобранном код озадачивает меня:

(gdb) disassemble sum0 
Dump of assembler code for function sum0(): 
    0x00000000000009de <+0>: push %rbp     ;prologue... 
    0x00000000000009df <+1>: mov %rsp,%rbp    ;prologue... 
    0x00000000000009e2 <+4>: movl $0x1,-0xc(%rbp)  ;initialize foo 
    0x00000000000009e9 <+11>: movl $0x2,-0x8(%rbp)  ;initialize bar 
    0x00000000000009f0 <+18>: mov -0xc(%rbp),%edx  ; 
    0x00000000000009f3 <+21>: mov -0x8(%rbp),%ecx  ; 
    0x00000000000009f6 <+24>: mov %edx,-0x14(%rbp)  ; This is unexpected 
    0x00000000000009f9 <+27>: movd -0x14(%rbp),%xmm1  ; why moving variables 
    0x00000000000009fe <+32>: mov %ecx,-0x14(%rbp)  ; to extended registers? 
    0x0000000000000a01 <+35>: movd -0x14(%rbp),%xmm2  ; 
    0x0000000000000a06 <+40>: add %ebx,%eax    ; add (as expected) 
    0x0000000000000a08 <+42>: movd %xmm0,%edx   ; copying the wrong result to ret 
    0x0000000000000a0c <+46>: mov %edx,-0x4(%rbp)  ; "  " "  "  " " 
    0x0000000000000a0f <+49>: mov -0x4(%rbp),%eax  ; "  " "  "  " " 
    0x0000000000000a12 <+52>: pop %rbp     ; 
    0x0000000000000a13 <+53>: retq 
End of assembler dump. 

Как и ожидалось, функция sum0() возвращает неправильное значение.

Любые мысли? Что происходит? Как все исправить?

- EDIT - на основе @MarcGlisse комментарий, я попробовал:

static inline uint32_t sum0() { 
    uint32_t foo = 1, bar=2; 
    uint32_t ret; 
    __asm__ __volatile__ (
     "add %%ebx,%%eax" 
     : "=a"(ret)    // ouput 
     : "a"(foo), "b"(bar)  // input 
     : "eax"     // modify 
    ); 
    return ret; 
} 

кажется, что учебник я следовал обманчиво. «eax» в поле ввода/ввода не означает самого регистра, но аббревиатуры e, a, x в таблице аббревиатуры.

В любом случае, я все еще не понимаю. Приведенный выше код приводит к ошибке компиляции: операнд «asm» имеет невозможные ограничения.

Я не понимаю, почему.

+0

Включение оптимизаций может облегчить понимание этой вещи? –

+0

«eax» не означает, что вы думаете, что он делает, вы хотите «a». И нет необходимости отмечать выходы как сбитые. –

+1

Прочтите более внимательно: «нет необходимости отмечать выходы как сбитые». –

ответ

2

Расширенные встроенные ограничения сборки для x86 указаны в official documentation.
complete documentation также стоит прочитать.

Как вы можете видеть, ограничения - это все отдельные буквы.
Ограничение «EAX» Ф.О. foo определяет три ограничения:

a
   The a register.

x
   Any SSE register.

e
   32-bit signed integer constant, or ...

Так вы говорите, что GCC eax будет затерт он не может поставить входной операнд там, и он выбирает xmm0.

When the compiler selects the registers to use to represent the input operands, it does not use any of the clobbered registers

proper constraint is simply "a".
Вам необходимо удалить eax (кстати, это должно быть rax из-за обнуления верхних бит) от clobbers (и добавить «cc»).

+0

Спасибо! Я отредактировал вопрос, чтобы показать полученный код – Chocksmith

+0

@Chocksmith Рад помочь. Вы редактируете, однако, избыточно, поскольку пометить мой ответ как принятый - это все, что необходимо, чтобы сообщить, что оно решило вашу проблему. Я откатываю ваше редактирование, чтобы оно соответствовало рекомендациям SO :) Это также поможет будущим читателям с той же проблемой –