Вывод десятичного числа

Тема в разделе "WASM.BEGINNERS", создана пользователем dcc0, 26 дек 2022.

  1. dcc0

    dcc0 Member

    Публикаций:
    2
    Регистрация:
    22 дек 2022
    Сообщения:
    60
    Решил чуть-чуть почитать про Ассемблер и что-нибудь закодировать. Честного говоря, думал, что не сумею.
    Два дня помучился, почти три. Рыл, ковырял, читал, больше искал примеры. Хотел попробовать синтаксис Intel (мне показался несколько более человечным нежели AT&T). Но всё-таки получилось сделать вывод десятичного числа на основе примеров, конечно. Правда, с отправкой остатка в стек не совсем разобрался, как в примерах.
    Зато сразу вывод с реверсом получился.


    Код (Text):
    1.  
    2. section .text
    3. global _start   ;must be declared for using gcc
    4. _start:         ;tell linker entry point
    5.    mov eax, 3111;Добавим 1234 - делимое в обратном порядке, то есть 4321. Выводить будем остаток от деления
    6. mov edi, 0
    7. loop:
    8.     inc edi       ; Инкремент, чтобы потом записать в строку все значения
    9.     mov ebx, 10   ; Запишем делитель в цикл, чтобы вернуть ему значение в новой итерации
    10.     xor edx, edx  ; Обнулим остаток
    11.     div ebx       ; Делим
    12.     add edx, 30h      ; Добавим 0 для вывода
    13.     mov  [stroka + edi], edx  ;Пишем в строку остаток
    14.     cmp eax,  0   ; Выходим
    15.     jne loop      ; Возврат в цикл
    16.  
    17.     mov ecx, stroka
    18.     mov     edx, 5 ; Размер вывода 5 (видимо, в байтах)
    19.     mov     ebx, 1 ; file descriptor (stdout)
    20.     mov     eax, 4 ; system call number (sys_write)
    21.     int       0x80 ; call kernel
    22.     mov     eax, 1 ;system call number (sys_exit)
    23.     int     0x80    ;call kernel
    24. section .data
    25.      segment .bss;
    26.   stroka resb 5;
    27.  
    Хотя, вероятно, лучше положить в цикле остаток в стек?! И затем прочитать каждое значение стека. Ещё странно, если использовать декремент, то потом вывод из буфера будет только одного значения (видимо, что-то не так делаю с декрементом). По идее значения в [stroka + edi] должны записываться в конце строки при декременте, так и есть, и вывод вроде бы правильный, но только одно значение выводится. Видмо, что-то с преобразованием числа (с нулём, может быть ) не додумал.

    Ассемблер nasm (под Linux 64).
    Команда сборки и выполнения: nasm -f elf64 print_number.asm -o print_number.o; ld -o print_number print_number.o; ./print_number

    P.S.
    Чем-то Ассемблер шахматы напоминает. У меня такая ассоциация.

    Спасибо всем. Спасибо, что вы есть.

    Update:
    Ещё обнаружил, что вызывать ядро стоит 1 раз, а не каждый раз, как было в моём первом примере в цикле. Код отредактировал.
    Нашёл здесь:
    https://acm.mipt.ru/twiki/bin/view/Asm/PrintIntFunction

    Update:
    Интересно. Если в регистр eax заносить значения из стека, то можно найти первое полезное применение, вроде того:
    Код (Text):
    1. mov eax, [rsp +17]              
    2. add eax, [rsp +15]
    Получаем генератор псевдослучайных чисел.
     
    Последнее редактирование: 27 дек 2022
  2. dcc0

    dcc0 Member

    Публикаций:
    2
    Регистрация:
    22 дек 2022
    Сообщения:
    60
    Сделал. Снова почти наугад :)
    Если в этой инструкции писать в строку регистр dl (не понял, почему именно его, а не edx целиком)
    Код (Text):
    1. mov  [stroka + edi], dl
    и при этом обратить инкремент регистра edi в декрмент, то строка выводится так как надо.

    Код (Text):
    1.  
    2. ; Программа печатает целое число
    3. ; Работает так: 1) Число делится на 10. 2) В регистр edx заносится остаток, в eax остальная часть.
    4. ; 3) Остаток записывается в stroka, начиная с конца, используется декремент, затем выводится
    5. ; 4) Если использовать инкремент, то строка будет напечатана в обратном порядке
    6. section .data
    7.   stroka db 4;
    8. section .text
    9. global _start  ;must be declared for using gcc
    10. _start:                  ;tell linker entry point
    11. mov eax, 311 ;Добавим 311 - делимое
    12. mov edi, 3
    13. loop:
    14.       dec edi               ; Декремент, чтобы потом записать в строку все значения
    15. mov ebx, 10         ; Запишем делитель в цикл, чтобы вернуть ему значение в новой итерации
    16.     xor edx, edx         ; Обнулим остаток
    17.     div ebx                ; Делим
    18.     add edx, 30h
    19.     mov  [stroka + edi], dl ; Пишем в строку остаток в обратном порядке
    20.   cmp edi,  0           ; Выходим
    21.     jne loop                ; Возврат в цикл
    22.   mov ecx, stroka
    23.     mov     edx, 4      ; Размер вывода 5 (видимо, в байтах)
    24.     mov     ebx, 1      ; file descriptor (stdout)
    25.     mov     eax, 4      ; system call number (sys_write)
    26.     int       0x80         ; call kernel
    27.     mov     eax, 1      ;system call number (sys_exit)
    28.     int     0x80           ;call kernel
    29.  
    30.  
     
    Последнее редактирование: 26 дек 2022