2014-11-13 7 views
0

Я изучаю ia-32, и все было хорошо на 32-битном Ubuntu, но я переключился на 64-битный и начал использовать флаг -m32, и теперь я не могу использовать DIV где угодно, нет это вопрос содержания регистров, он всегда дает исключение с плавающей запятой ... И я уверен, что я не делю на ноль. Я использую gcc и gdb.fpu ia-32, исключение с плавающей запятой

Это самый близкий вопрос к моей проблеме: FPU IA-32 SIGFPE, Arithmetic exception

Я пытался поставить инструкции fldcw с 0x220, но не имеет никакого значения.

Мой исходный код:

.section .text 

Division: 
    .int 0x220 

str: 
    .asciz "%d" 

.global binario    # void binario(int) 

binario: 
    pushl %ebp   # prologo 
    movl %esp,%ebp   # 

    finit 
    fldcw Division 

    pushl %ebx 
    pushl %ecx 
    pushl %edx 

    movl 8(%ebp),%eax  # param x to eax 

    cmpl $0,%eax   # compare x with 0 
    je fim    # return recursive call 

    movl $2,%ecx   # prepare division 
    divl %ecx   # divide eax with 2 

    movl $0,%ecx   # clean ecx 
    movb %al,%cl   # put division result on cl 

    pushl %ecx   # push x/2 
    call binario   # recursive call 
    add $8,%esp   # clean esp 

    movl $0,%ecx   # clean ecx 
    movb %ah,%cl   # put division rest on cl 

    pushl %ecx   # push division rest 
    pushl $str   # push string 
    call printf   # call printf function 
    addl $8,%esp   # clean esp 

fim: 

    pushl %edx 
    pushl %ecx 
    pushl %ebx 

    movl %ebp,%esp   # epilogo 
    popl %ebp    # 
    ret 

GDB журнала:

28  divl %ecx   # divide eax with 2 
2: $ecx = 2 
1: $eax = 33 
(gdb) 

Program received signal SIGFPE, Arithmetic exception. 
binario() at ex08.s:28 
28  divl %ecx   # divide eax with 2 
2: $ecx = 2 
1: $eax = 33 

ответ

3

+1 для поиска SO и с помощью отладчика, -1 для не читает множество ссылок инструкции;)

Используемый вами вариант div r/m32 делит 64-битное количество, сформированное из edx (верхние 32 бита) и eax (низкие 32 бита). Кроме того, вы также получаете это исключение, если ваш результат за пределами допустимого диапазона. Проблема в том, что вы не обнуляете edx, поэтому он имеет некоторое случайное значение, которое приводит к переполнению всего деления. Вам необходимо очистить edx (нуль-удлинител eax) до беззнакового деления и подписать-удлинить eax до edx перед подписанием деления.

PS: Надеюсь, вы не используете div, чтобы разделить на 2. Чтобы разделить или умножить силы на 2, вы должны использовать сдвиги.

+0

Да! Он работал путем обнуления edx. И да, сначала я использовал смены, но тогда мне понадобилась остальная часть деления, чтобы преобразовать int в двоичный файл, так что мне нужно% ах. Я слишком мало читаю из набора команд T.T, это правда. Мне стыдно. – Vcoder

+1

'SHR' возвращает сдвинутый бит в флагом переноса (' CF'). Также вы можете получить LSB перед сменой маскировки. Для двоичного преобразования вы можете просто использовать shift left, чтобы получить бит в правильном порядке без какой-либо рекурсии и т. Д. – Jester