Раздел «Язык Ассемблера».PrintIntFunction:

Программа печати целого числа на NASM

Данная программа имеет простую логику: считывает целое число и выводит его. Но в коде вместо описания функции scan_int стоит "заглушка", которая всегда возвращает 133.

Задача. Напишите правильную реализацию функции scan_int. Логика этой функции должна быть такой, как в приведённой ниже программе на Си.

Задача. Добавьте в функции NASM print_int, scan_int возможность считывания и печати отрицательных целых чисел.

Задача "a*b". Напишите программу на NASM, которая считывает два целых числа и выводит результат их сложения и умножения. Используйте результаты предыдущей задачи.

Задача. Напишите реализации функции scan_hex и print_hex на языках NASM и Cи. В реализациях на языке Си используйте функции write и read (см. man 2 read и man 2 write). Постарайтесь сделать логику программ на Си и на NASM максимально близкой.

section .bss
    buffer resb 20

section .text
global _start
_start:
    call scan_int   ; читать int  из stdin в регистр eax
    push eax        ; поместить eax в стек — это будет 
                    ; аргументом для следующей функции

    call print_int  ; напечатать int, который находится в вершине стека
                    ; в стандартный поток вывода
                    ; "call func" эквивалентно 
                    ;    push <адрес_следующей_инструкции>;
                    ;    jmp func

    mov eax, 1      ; Эти три строчки эквиваленты exit(0)
    mov ebx, 0      ;
    int 0x80        ;

scan_int:           ; эта функция должна читать int из stdin,
    mov eax, 133    ; но пока она не реализована и просто 
    ret             ; возвращает число 133

print_int:          ; функция печати целого числа в stdout
                    ; аргумент (4-байтовое целое число)
                    ; находится в вершине стека
    ; ebp содержит адрес начала stack frame
    ; esp содержит адрес вершины стека
    ; esp < ebp, то есть вершина имеет меньший адрес
    ; в начале по адресам (ebp-4, ebp-3, ebp -2, ebp -1) лежат
    ; четыре байта целого числа, которое нам передали 
    ; в качестве аргумента

    push ebp        ; поместим в стек адрес начала стека 
                    ; этот push автоматически делает esp -= 4 
    mov ebp, esp    ; теперь ebp равно esp 
                   
                     ; аргумеенты находятся по адресу ebp + 8
    mov ecx, [ebp+8] ; значение переданного нам целого числа поместим в ecx

    xor edx, edx     ; обнулим edx
    mov esi, 10      ; на 10 мы будем делить.

    mov edi, 18      ; символы-цифры нашего числа мы будем помещать
                     ; по адресам buffer + 17, buffer+16, buffer+15, ...

    mov byte [buffer + 18], 0xA ; 19-й и 20-й символы — это перенос строчки
    mov byte [buffer + 19], 0   ; и символ конца строки

.loop:
    mov eax, ecx   ;
    xor edx, edx   ; данные четыре строки дают
    div esi        ;   ecx = ecx / 10 
    mov ecx, eax   ;


    add edx, '0'  ; '0' ассемблером интерпретируется как ASCII код символа '0'
    dec edi
    mov byte [buffer+edi], dl
    cmp ecx, 0
    jne .loop

    mov eax, 4        ; эквивалентно write( 1, buffer + edi, 19 - edi )
    mov ebx, 1
    mov ecx, buffer   ; можно короче — lea ecx, [buffer+edi]
    add ecx, edi
    mov edx, 19
    sub edx, edi
    int 0x80

    leave       ; эквивалентно  mov esp, ebp
                ;               pop ebp 
    ret         ; эквивалентно  pop IP 
                ;               

Считывание целого положительного числа на Си без использования scanf

 

#include <unistd.h>
char buffer[20];
int scan_int() {
   int a = 0;
   do {
       int c;
       int ret = read( 2, buffer, 1 );
       c = buffer[0];
       if( ret > 0 && c != '\n' ) {
           a *= 10; 
           a += c - '0'; 
       } else {
           break;
       }
   } while(1);
   return a;
}

int print_int(int a) { 
   int c;
   int i = 20;
   buffer[--i] = 0;
   buffer[--i] = '\n';
   
   do {
       c = a % 10;
       a /= 10;
       c += '0';
       buffer[--i] = c;
   } while( a );
   write( 1, buffer + i, 20 - i );
   return a;
}
int main() {
    int a = scan_int();
    print_int( a );
}