global _start %define STDIN 0 %define STDOUT 1 %define STDERR 2 section .data src db 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 src_size equ $-src ; резервируем 1 килобайт для буффера ввода и вывода ; также в отдельной переменной сохраняем размер этого буфера print_buf: times 1024 db 0 buf_size equ $-print_buf section .text %macro DIGIT_TO_ASCII 1 ; макрос, принимающий один регистр add %1, '0' %endmacro %macro PUSH_M 1-* ; push many; пушит в порядке следования %rep %0 push %1 %rotate 1 %endrep %endmacro %macro POP_M 1-* ; pop many. читает в порядке следования %rep %0 pop %1 %rotate 1 %endrep %endmacro %macro RPOP_M 1-* ; pop many. читает в обратном порядке %rotate -1 %rep %0 pop %1 %rotate -1 %endrep %endmacro ; Передачу аргументов будем делать при помощи ABI - стандартная практика для linux ; Аргументы передаются в следующем порядке: rdi, rsi, rdx, rcx, r8, r9. Все, что не влезло, пушится в стек ; У передачи через стек тоже есть особенности, но их мы пока касаться не будем print_from_buf: ; word -> void PUSH_M rax, rsi, rdx, rdi ; сохраним регистры, которые точно попортим mov rdx, rdi ; сколько выводить, в rdi содержится единственный аргумент mov rsi, print_buf ; откуда выводить. Адрес буфера mov rdi, STDOUT; куда выводить. Дескриптор файла. В нашем случае стандартного вывода mov rax, 1 syscall RPOP_M rax, rsi, rdx, rdi ; вернем значения регистров ret _start: mov rcx, src_size mov rsi, src mov rdi, print_buf xor rax, rax ; обнуляем регистр .transfer: ; в цикле передаем данные, попутно конвертируя их в ascii lodsb DIGIT_TO_ASCII rax stosb loop .transfer mov [rdi + 1], BYTE `\n` ; Чтобы система не ругалась на отсутствие переноса mov rdi, src_size call print_from_buf exit: mov rax, 60 mov rdi, 0 syscall