Linux x86 NASM - Подпрограмма: распечатать слово от EAX
Так что я'я изучаю сборку Linux x86 с синтаксисом NASM (О боже, не это снова, вы'все думают) Я'Я пытаюсь создать подпрограмму, которая будет просто выводить значение в EAX на стандартный вывод. Код запускается и завершается без ошибок, но ничего не печатается. Я могу'не понимаю, почему. Прежде всего, вот файл, который яработаю в:
segment .bss
to_print: resd 1
segment .text
global print_eax_val
print_eax_val: ; (top)
push dword ebx ;Stack: edx
push dword ecx ; ecx
push dword edx ; ebx
; (bot)
mov ecx,eax ;ecx = eax
mov [to_print],ecx ;to_print = ecx
mov eax, 4 ;sys_write
mov ebx, 1 ;to stdout
add ecx, 47 ;add 47 for ASCII numbers
mov edx, 2 ;double word = 2 bytes
int 0x80
mov eax, [to_print] ;eax = original val
pop edx ;pop the registers back from the stack
pop ecx
pop ebx ;Stack: empty
ret
Это вызывается из моего основного файла, который выглядит следующим образом (это, вероятно, не имеет значения, если я нея что-то упустил).
segment .data
hello db "Hello world!", 0
newline db 0xA
len equ $ - hello
len2 equ $ - newline
segment .text
extern print_nl
extern print_eax_val
global main
main:
enter 0,0
call print_nl
mov eax, 1
call print_eax_val
mov ebx, 0 ;exit code = 0 (normal)
mov eax, 1 ;exit command
int 0x80 ;ask kernel to quit
print_nl
это просто еще одна подпрограмма, которая определяет и печатает новую строку. Это успешно выполняется и печатает новую строку, как ожидалось.
Проблема связана с параметром длины для моегоsys_write
вызов? Я'м, давая ему 2, который является размеромdword
, который является размером какEAX
зарегистрироваться и мойto_print
ярлык, который я зарезервировалresd 1
, Я пытался изменить длину до 1, 4, 8, 16 и 32 из отчаяния ... Ничего не получалось.
РЕДАКТИРОВАТЬ: Для тех, кто интересуется, вот как я исправил код: (Я буду ставить звездочки на строки, которые я изменил):
segment .bss
to_print: resd 1
segment .text
global print_eax_val
print_eax_val: ; (top)
push dword ebx ;Stack: edx
push dword ecx ; ecx
push dword edx ; ebx
; (bot)
mov ecx,eax ;ecx = eax
mov [to_print],ecx ;to_print = ecx
**** add dword [to_print], 48
mov eax, 4 ;sys_write
mov ebx, 1 ;to stdout
**** mov ecx, to_print
mov edx, 2
int 0x80
**** sub dword [to_print], 48
mov eax, [to_print] ;eax = original val
pop edx ;pop the registers back from the stack
pop ecx
pop ebx ;Stack: empty
ret
В принципе,ecx
должен содержатьадрес блока, который вы хотите напечатать, а не само значение. Как указано в выбранном ответе, это будеттолько работать, если eax находится в диапазоне 0-9.
РЕДАКТИРОВАТЬ 2Так что я был немного озадачен вторым параметром для sys_write (который хранится вedx
). Я думаю, что это просто относится к числу байтов. Так что дляdword
, как я использовал, было бы правильно использовать 4 там, потому что двойное слово составляет 4 байта или 32 бита. Я'Я предполагаю, что это сработало, потому что x86 имеет младший порядок. Так в памяти шестнадцатеричное значениеto_print
будет выглядеть так:
90 00 00 00
И с предоставленной длиной два, sys_write получает:
90 00
Так что ценность, к счастью, нене испортился.
Я позже изменил код для храненияto_print
вместо этого, используя байтresb 1
и доступ к нему с помощьюbyte
вместоdword
... Байт здесь хорошо, потому что я знаю, чтоя не собираюсь даватьto_print
значение выше 9.I '