2012-04-27 16 views
21

Obecnie piszę prosty kompilator C, który pobiera plik .c jako dane wejściowe i generuje kod zespołu (składnia X86, AT & T). Wszystko jest dobre, ale kiedy próbuję wykonać instrukcję IDIVQ, otrzymuję wyjątek zmiennoprzecinkowy. Oto mój wkład:Zespół X86 - Obsługa instrukcji IDIV

int mymain(int x){ 
    int d; 
    int e; 
    d = 3; 
    e = 6/d; 
    return e; 
} 

I tu jest mój wygenerowany kod:

mymain: 
.LFB1: 
    .cfi_startproc 
    pushq %rbp 
    .cfi_def_cfa_offset 16 
    movq %rsp, %rbp 
    .cfi_offset 6, -16 
    .cfi_def_cfa_register 6 
    movq %rdi, -40(%rbp) 
    movq $3, -8(%rbp) 
    movq $6, %rax 
    movq -8(%rbp), %rdx 
    movq %rdx, %rbx 
    idivq %rbx 
    movq %rax, -16(%rbp) 
    movq -16(%rbp), %rax 
    leave 
    .cfi_def_cfa 7, 8 
    ret 
    .cfi_endproc 
.LFE1: 
    .size mymain, .-mymain 

Według http://www.cs.virginia.edu/~evans/cs216/guides/x86.html, idivq% RBX powinna produkować 6/D (iloraz) w % Rax. Ale otrzymuję wyjątek zmiennoprzecinkowy i nie mogę znaleźć problemu.

Każda pomoc będzie doceniona!

+0

Nie ma związku z tym pytaniem, ale czy powinieneś robić 'movq% rdi, -40 (% rbp)' bez regulacji rejestru 'esp'? Czy to jest w porządku ze względu na czerwoną strefę x64? –

Odpowiedz

23

The pierwsza część odpowiedzi Mysticials jest poprawna, idiv dokonuje podziału 128/64 bitów, więc wartość rdx, która przechowuje górny 64 bit od dywidendy, nie może zawierać losowej wartości. Ale zerowe rozszerzenie jest niewłaściwą drogą.

Jak masz podpisane zmiennych, trzeba znak przedłużyć rax do rdx:rax. Istnieje szczególna instrukcja dotycząca tego, cqto (konwersji kwadratu na oś) w AT & T i cqo w składni Intel. Nowsze wersje AFAIK gazu akceptują obie nazwy.

+0

+1 Zabawne, jak przeoczyłem podpisaną część. – Mysticial

+0

Rzeczywiście, przeprowadzałem testy i napotkałem błąd podczas obsługi podpisanych wartości. Nie widziałem wcześniej tej instrukcji, ale wydaje się, że teraz rozwiązuje to zagadnienie. Dziękuję Ci! –

+0

@Mysticial Zdarza się nawet najlepiej :-) – hirschhornsalz

11

Instrukcja idivq dzieli 128-bitową liczbę całkowitą (rdx:rax) przez operand.

  • rax zawiera niższe 64-bitowe dywidendy.
  • rdx zawiera górne 64-bitowe dywidendy.

Gdy iloraz nie mieści się w 64-bitach, wyrzuci wyjątek zmiennoprzecinkowy.

Więc co trzeba zrobić, to zerowy rdx:

movq %rdx, %rbx 
xorq %rdx, %rdx # zero "rdx" 
idivq %rbx 

Jeśli masz do czynienia z podpisanych liczb całkowitych, należy również do podpisania przedłużenia rax do rdx:rax, czyli kopiowanie bitu rax migowego do każdego kawałka rdx i jest realizowane cqo alias cqto:

movq %rdx, %rbx 
cqo 
idivq %rbx 
+5

Zeroing rdx będzie działał z liczbami dodatnimi, ale w przypadku ujemnego rax prawdopodobnie potrzebne jest rdx = -1 ... Czyż nie? – marekb

+5

Myślę, że markab ma rację - czyż nie powinno się "xorq" napisać instrukcji "cqo", by podpisać rozszerzenie 'rax' na' rdx: rax'? –

+0

W tym przypadku przy podpisanym pisaniu: myślę, że tak. –

Powiązane problemy