сборка носа: не может найти допустимые значения для всех меток после 1004 проходов - PullRequest
1 голос
/ 11 октября 2019

Я пытаюсь написать ассемблерный код x86 для ассемблера NASM, который преобразует шестнадцатеричное число в строку и печатает его. Для простоты я предположил, что мое шестнадцатеричное число будет содержать только цифры (например, 0x1234). Вот код:

print_hex.asm


    [org 0x7c00]

    mov dx, 0x1234
    call print_hex

    jmp $

    print_hex:
        push bx
        push cx
        push dx
        push ax

        mov bx, HEX_STR
        mov cx, 0x000f
        mov ax, 0x0000  ; length counter

    loop: 
        push bx         ; save bx
        and cx, dx      ; 0xabcd & 0x000f
        add bx, 5       ; find position in the template
        sub bx, ax
        add [bx], cl 
        pop bx
        shr dx, 4       ; next digit
        mov cx, 0x000f
        inc ax          ; increment counter
        cmp ax, 4
        jl loop         ; loop through the digits

        pop ax

        call print_string

        pop dx
        pop cx
        pop bx
        ret


    %include "print_string.asm"

    HEX_STR:           ; template string
        db '0x0000', 0

    times 510-($-$$) db 0
    dw 0xaa55

print_string.asm


    print_string:
        mov ah, 0x0e
        push bx

        loop:
            cmp BYTE [bx], 0
            je end
            mov al, [bx]
            int 0x10
            inc bx
            jmp loop

        end:
            pop bx
            ret

Если я попытаюсьпри сборке / компиляции print_hex.asm с NASM выдается следующая ошибка:

print_hex.asm: ошибка: не удается найти допустимые значения для всех меток после 1004 проходов, отказавшись.

print_hex.asm: ошибка: возможные причины: рекурсивные эквалайзеры, неправильное использование макросов.

Я заметил, что я не использую какие-либо метки (например, метку цикла), код работает нормально.

1 Ответ

1 голос
/ 11 октября 2019

Ваша настоящая проблема в том, что вы определили метку loop: дважды.
NASM 2.14.02 выводит красивое сообщение об ошибке:

$ nasm print_hex.asm 
print_string.asm:5: error: label `loop' inconsistently redefined
print_hex.asm:19: note: label `loop' originally defined here

Препроцессор %includeДиректива работает так же, как в C #include: источники фактически становятся частью одного и того же файла, разделяя одно и то же пространство имен для символов.

Предположительно, у вас есть более старая версия NASM, которая напечатала безумное и бесполезное сообщение об ошибке. IDK, если это связано с тем, что loop также является мнемоникой инструкции. Так не должно быть, но трудно представить, чтобы NASM имел такую ​​бесполезную обработку дублирующих меток в любой последней версии. Это довольно распространенная ошибка в рукописном асме, и именно на этом обычно используется NASM. Так что, возможно, у NASM была ошибка, которая пробралась loop за обычное обнаружение дубликатов и заставила его попытаться потерпеть неудачу.

loop: устраняет неоднозначность строки как метки, а не строки инструкции для NASM. (Но не YASM: он не позволит использовать loop: в качестве метки)


Использовать локальные имена меток

.loop: относится к предыдущей нелокальной метке,Так что это как сокращение для print_hex.loop и print_string.loop как в объявлении, так и в использовании.

https://www.nasm.us/doc/nasmdoc3.html#section-3.9


Проверка кода

Кстати, ваш коддовольно раздутыйВам не нужно сохранять / восстанавливать каждый регистр в каждой функции;просто дайте им забить regs.

Кроме того, вы можете конвертировать int-> hex более эффективно, без необходимости добавления шаблона. (Начальная 0x удобна, но остальное вы можете рассчитать в рег). Кроме того, я не думаю, что ваш код обрабатывает разделение 0..9 против a..f: эти диапазоны кодов символов ASCII, к сожалению, не соседствуют друг с другом.

См. Как преобразовать числов шестнадцатеричный формат? для простой 32-битной версии вы можете легко портировать на 16-битную, с таблицей подстановки или с условной обработкой 0,9 против a..f. Смотрите также https://codegolf.stackexchange.com/revisions/193842/1 для простой версии с условной ветвью. (Более поздняя версия сохраняет еще больший размер кода с использованием DAS).

Используйте небольшие константы в качестве непосредственных операндов, таких как and al, 0xf, вместо помещения их в CX. Если хотите, уменьшите указатель с конца буфера, или с помощью шестнадцатеричного числа вы можете использовать вращение, чтобы получить откусывание сверху и генерировать в порядке печати. ​​

...