2012-04-27 2 views
21

В настоящее время я пишу простой компилятор C, который принимает .c файл в качестве входных данных и генерирует код сборки (X86, AT & T синтаксис). Everyting хорошо, но когда я пытаюсь выполнить команду IDIVQ, я получаю исключение с плавающей запятой. Вот мой вклад:X86 assembly - Обработка инструкции IDIV

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

А вот мой сгенерированный код:

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 

Согласно http://www.cs.virginia.edu/~evans/cs216/guides/x86.html, idivq% RBX следует производить 6/сут (Факторпространство) в % бараков. Но я получаю исключение с плавающей точкой, и я не могу найти проблему.

Любая помощь будет очень признательна!

+0

Не относится к этому вопросу, но вы должны делать 'movq% rdi, -40 (% rbp)' без корректировки регистра 'esp'? Или это нормально из-за «красной зоны» x64? –

ответ

23

первая часть ответа Mysticals верна, idiv выполняет деление 128/64 бит, поэтому значение rdx, которое содержит верхний бит 64 бит от дивиденда, не должно содержать случайное значение. Но нулевое расширение - неправильный путь.

Как вы уже подписанных переменных, вам нужно знака продлить rax на rdx:rax. Для этого есть специальная инструкция: cqto (конвертировать квадрат в октябрь) в AT & T и cqo в синтаксисе Intel. AFAIK более новые версии газа принимают оба названия.

movq %rdx, %rbx 
cqto     # sign extend rax to rdx:rax 
idivq %rbx 
+0

+1 Забавно, как я упустил подписанную часть. – Mysticial

+0

Действительно, я выполнял свои тесты и обнаружил ошибку при обработке подписанных значений. Я не видел эту инструкцию раньше, но, похоже, сейчас она решает проблему. Спасибо! –

+0

@Mysticial Бывает даже к лучшему :-) – hirschhornsalz

11

Инструкция idivq делит 128-битное целое число (rdx:rax) на операнд.

  • rax содержит нижние 64-бит дивиденда.
  • rdx содержит верхние 64-бит дивиденда.

Когда фактор не вписывается в 64-битные, он будет вызывать исключение с плавающей запятой.

Так что вам нужно сделать, это ноль rdx:

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

Если вы имеете дело с целыми числами, вы также должны подписать продлить rax в rdx:rax, что означает копирование битого rax знака чтобы каждый бит rdx и осуществляется с cqo псевдонимом cqto:

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

Zeroing rdx будет работать с положительными числами, но в случае отрицательного rax, вероятно, требуется rdx = -1 ... Разве это не так? – marekb

+5

Я думаю, что marekb прав - не должно ли 'xorq' instrcution быть инструкцией' cqo', чтобы подписать расширение 'rax' в' rdx: rax'? –

+0

В этом случае с подписанным типом: я так думаю. –