ASM rozwiaznia

Zestaw 1 - wstęp do programowania w NASM

Rozwiązania

Zadanie 1

%include "asm_io.inc"
section .data
;
; dane zainicjalizowane
hello: db "Hello",0
;

section .bss
;
; dane niezainicjalizowane
;

section .text
global _asm_main
_asm_main:
enter 0,0 ; setup 
pusha

;
; Właściwy kod wstawiamy tu. 

mov eax,hello
call print_string

;mov ah, 9
;mov dx, hello
;int 0x21            ; to nie przejdzie: wywołaj przerwanie 0x21 - po załadowaniu 9 do AH wyświetlona będzie 

; Nie należy modyfikować kodu przed i po tym komentarzu
;

popa
mov eax, 0 ; powrót do C
leave
ret

    ; nasm -f bin -o czesc.com czesc.asm

    org 100h

        mov    ah, 9        ; funkcja wyświetlania na ekran
        mov    dx, jak_masz    ; co wyświetlić
        int    21h        ; wyświetl

        mov    ah, 0ah    ; funkcja pobierania danych z klawiatury
        mov    dx, imie    ; bufor na dane
        int    21h        ; pobierz dane

        mov    ah, 9
        mov    dx, czesc
        int    21h        ; wyświetl napis "Cześć"

        mov    ah, 9
        mov    dx, imie+2    ; adres wpisanych danych
        int    21h        ; wyświetl wpisane dane

        mov    ax, 4c00h
        int    21h

    jak_masz    db    "Jak masz na imie? $"
    imie    db 20        ; maksymalna liczba znaków do pobrania
        db 0        ; tu dostaniemy, ile znaków pobrano
        times 22 db "$"    ; miejsce na dane

    czesc        db    10, 13, 10, 13, "Czesc $"

Zadanie 2

; nasm -felf -o first.obj first.asm
; nasm -felf -o asm_io.obj asm_io.asm
; gcc -o driver.obj -c driver.c
; gcc -o first.exe first.obj driver.obj asm_io.obj
;

%include "asm_io.inc"
;
; initialized data is put in the .data segment
;
segment .data
;
; These labels refer to strings used for output
;
prompt1 db    "Enter a number: ", 0       ; don't forget nul terminator
prompt2 db    "Enter another number: ", 0
outmsg1 db    "You entered ", 0
outmsg2 db    " and ", 0
outmsg3 db    ", the sum of these is ", 0


;
; uninitialized data is put in the .bss segment
;
segment .bss
;
; These labels refer to double words used to store the inputs
;
input1  resd 1
input2  resd 1

 

;
; code is put in the .text segment
;
segment .text
        global  _asm_main
_asm_main:
        enter   0,0               ; setup routine
        pusha

        mov     eax, prompt1      ; print out prompt
        call    print_string

        call    read_int          ; read integer
        mov     [input1], eax     ; store into input1

        mov     eax, prompt2      ; print out prompt
        call    print_string

        call    read_int          ; read integer
        mov     [input2], eax     ; store into input2

        mov     eax, [input1]     ; eax = dword at input1
        add     eax, [input2]     ; eax += dword at input2
        mov     ebx, eax          ; ebx = eax
        dump_regs 1               ; dump out register values
        dump_mem 2, outmsg1, 1    ; dump out memory
;
; next print out result message as series of steps
;
        mov     eax, outmsg1
        call    print_string      ; print out first message
        mov     eax, [input1]     
        call    print_int         ; print out input1
        mov     eax, outmsg2
        call    print_string      ; print out second message
        mov     eax, [input2]
        call    print_int         ; print out input2
        mov     eax, outmsg3
        call    print_string      ; print out third message
        mov     eax, ebx
        call    print_int         ; print out sum (ebx)
        call    print_nl          ; print new-line

        popa
        mov     eax, 0            ; return back to C
        leave                     
        ret

Zadanie 3

;
; file: math.asm
; This program demonstrates how the integer multiplication and division
; instructions work.
;
; To create executable:
; nasm -f coff math.asm
; gcc -o math math.o driver.c asm_io.o

%include "asm_io.inc"

segment .data
;
; Output strings
;
prompt          db    "Enter a number: ", 0
square_msg      db    "Square of input is ", 0
cube_msg        db    "Cube of input is ", 0
cube25_msg      db    "Cube of input times 25 is ", 0
quot_msg        db    "Quotient of cube/100 is ", 0
rem_msg         db    "Remainder of cube/100 is ", 0
neg_msg         db    "The negation of the remainder is ", 0

segment .bss
input   resd 1


segment .text
        global  _asm_main
_asm_main:
        enter   0,0               ; setup routine
        pusha

        mov     eax, prompt
        call    print_string

        call    read_int
        mov     [input], eax

        imul    eax               ; edx:eax = eax * eax
        mov     ebx, eax          ; save answer in ebx
        mov     eax, square_msg
        call    print_string
        mov     eax, ebx
        call    print_int
        call    print_nl

        mov     ebx, eax
        imul    ebx, [input]      ; ebx *= [input]
        mov     eax, cube_msg
        call    print_string
        mov     eax, ebx
        call    print_int
        call    print_nl

        imul    ecx, ebx, 25      ; ecx = ebx*25
        mov     eax, cube25_msg
        call    print_string
        mov     eax, ecx
        call    print_int
        call    print_nl

        mov     eax, ebx
        cdq                       ; initialize edx by sign extension
        mov     ecx, 100          ; can't divide by immediate value
        idiv    ecx               ; edx:eax / ecx
        mov     ecx, eax          ; save quotient into ecx
        mov     eax, quot_msg
        call    print_string
        mov     eax, ecx
        call    print_int
        call    print_nl
        mov     eax, rem_msg
        call    print_string
        mov     eax, edx
        call    print_int
        call    print_nl
        
        neg     edx               ; negate the remainder
        mov     eax, neg_msg
        call    print_string
        mov     eax, edx
        call    print_int
        call    print_nl

        popa
        mov     eax, 0            ; return back to C
        leave                     
        ret

Zestaw 2 - Linux wejście/wyjście

Rozwiązania

Zadanie 1

; Program witający się z użytkownikiem po imieniu

;

; Autor: Bogdan D.

; kontakt: bogdandr (at) op (dot) pl

;

; kompilacja:

; nasm -f elf czesc.asm

; ld -s -o czesc czesc.o

;

section .text ; początek sekcji kodu

global _start ; _start będzie symbolem globalnym,

; od którego zacznie się wykonywanie programu

_start:

mov eax, 4 ; zapis do pliku

mov ebx, 1 ; na ekran

mov ecx, jak_masz ; napis do wyświetlenia: pytanie

mov edx, jak_masz_dl ; długość napisu

int 80h ; wyświetlamy

mov eax, 3 ; czytanie z pliku

mov ebx, 0 ; z klawiatury

mov ecx, imie ; dokąd czytać?

mov edx, imie_dl ; ile bajtów czytać?

int 80h ; wczytujemy

mov eax, 4 ; zapis do pliku

mov ebx, 1 ; na ekran

mov ecx, czesc ; napis do wyświetlenia: "cześć"

mov edx, czesc_dl ; długość napisu

int 80h ; wyświetlamy

mov eax, 4 ; zapis do pliku

mov ebx, 1 ; na ekran

mov ecx, imie ; napis do wyświetlenia: imię

mov edx, imie_dl ; długość napisu

int 80h ; wyświetlamy

mov eax, 1

xor ebx, ebx

int 80h

section .data ; początek sekcji danych

jak_masz db "Jak masz na imie? "

jak_masz_dl equ $ - jak_masz

; rezerwuj 20 bajtów o wartości początkowej zero, na imię

imie: times 20 db 0

imie_dl equ $ - imie

czesc db "Czesc "

czesc_dl equ $ - czesc

Zadanie 2

; Zadanie 2. Napisz program który otwiera plik do zapisu (jeżeli go nie ma to go tworzy)

; i wpisuje do niego tekst np. Twoje imię i nazwisko a następnie go zamyka.

;

; wersja NASM na system 64-bitowy (x86-64)

; kompilacja: nasm -felf64 hello64.asm -o hello64.o

; linkowanie: ld hello64.o -o hello64

bits 64

section .text ; początek sekcji kodu.

global _start ; linux rozpoczyna wykonywanie programu od etykiety _start

; musi ona być widoczna na zewnątrz (global)

_start: ; punkt startu programu

mov rax, 2 ; sys_open : otwarcie pliku

mov rdi, name ; nazwa pliku

mov rsi, 2101o ; tryb : w 1, utworz (100) plik do dopisywania (2000)

mov rdx, 777o ; prawa

syscall

mov [file], rax

mov rdi, rax

mov rax, 1 ; numer funkcji systemowej:

; sys_write - zapisz do pliku

mov rsi, tekst ; RSI = adres (offset) tekstu

mov rdx, dlugosc ; RDX = długość tekstu

syscall ; wywołujemy funkcję systemową

mov rax, 3

mov rdi, [file]

syscall

mov rax, 60 ; numer funkcji systemowej

; (sys_exit - wyjdź z programu)

syscall ; wywołujemy funkcję systemową

section .data ; początek sekcji danych.

tekst db "Czesc", 0ah ; nasz napis, który wyświetlimy

dlugosc equ $ - tekst ; długość napisu

name db "./data.txt",0 ;

file dd 0,0

; kod 32 bitowy
section .text ; początek sekcji kodu.
global _start ; linux rozpoczyna wykonywanie programu od etykiety _start

; musi ona być widoczna na zewnątrz (global)

_start: ; punkt startu programu
mov eax, 5 ; sys_open : otwarcie pliku
mov ebx, name ; nazwa pliku

mov ecx, 2101o ; tryb : w 1, utworz (100) plik do dopisywania (2000)
mov edx, 777o ; prawa
int 80h

mov [file], eax

mov eax, 4 ; numer funkcji systemowej:

mov ebx, [file]
mov ecx, tekst
mov edx, dlugosc
int 80h

mov eax, 6
mov ebx, [file]
int 80h

mov eax, 1 ; numer funkcji systemowej
; (sys_exit - wyjdź z programu)
int 80h ; wywołujemy funkcję systemową

section .data ; początek sekcji danych.

tekst db "Czesc", 0ah ; nasz napis, który wyświetlimy
dlugosc equ $ - tekst ; długość napisu
name db "./data.txt",0 ;
file dd 0,0

Zadanie 3

; Zadanie 3. Napisz program, który odczyta czas systemowy i wypisze aktualna godzinę.

; (Możesz wykorzystać wywołanie systemowe 13 lub 96).

; wersja NASM na system 64-bitowy (x86-64)

; kompilacja: nasm -felf64 time.asm -o time.o

; linkowanie: ld time.o -o time

bits 64

section .text ; początek sekcji kodu.

global _start ; linux rozpoczyna wykonywanie programu od etykiety _start

; musi ona być widoczna na zewnątrz (global)

_start: ; punkt startu programu

mov rax, 96 ; sys_gettimeofday

mov rdi, time ; adres struktury przechowujacej czas

mov rsi, strefa ; adres struktury przechowujacej strefe

syscall

test eax, eax ; sprawdzamy czy nie było błędu (eax != 0)

jnz koniec

; kolejno dzielimy eax i zapisujemy reszty z dzielenia w przygotowanym

; łańcuchu 'czas'

; (potem dziele rax ale mozna to zmienic na eax)

mov eax, [time.sekundy]

xor edx, edx

mov ebx, 10

div ebx

add edx, '0'

mov [czas + 7], dl

mov rbx, 6

xor rdx, rdx

div rbx

add rdx, '0'

mov [czas+6], dl

; minuty

mov rbx, 10

xor rdx, rdx

div rbx

add rdx, '0'

mov [czas+4], dl

mov rbx, 6

xor rdx, rdx

div rbx

add rdx, '0'

mov [czas+3], dl

; godziny

mov rbx, 24

add rax, 1 ; czas zimowy

xor rdx,rdx

div rbx

mov rax, rdx

mov rbx, 10

xor rdx, rdx

div rbx

add rdx, '0'

mov [czas+1], dl

add ax, '0'

mov [czas], al

; wypisuje na ekran

mov rax, 1

mov rdi, 1

mov rsi, czas

mov rdx, dlugosc

syscall

koniec:

mov rax, 60 ; numer funkcji systemowej

; (sys_exit - wyjdź z programu)

syscall ; wywołujemy funkcję systemową

section .data ; początek sekcji danych.

time:

.sekundy dd 0

.milisek dd 0

strefa dd 0, 0 ; strefa to dwa inty

czas db "gg:mm:ss",0ah

dlugosc equ $- czas

section    .text            ; początek sekcji kodu.
global _start                ; linux rozpoczyna wykonywanie programu od etykiety _start
                                 ; musi ona być widoczna na zewnątrz (global)

_start:                ; punkt startu programu
    mov eax, 13 
    int 80h   

cdq
mov ebx,10
div ebx
add dl,'0'
mov [wynik+7],dl

cdq
mov ebx,6
div ebx
add dl,'0'
mov [wynik+6],dl

cdq
mov ebx,10
div ebx
add dl,'0'
mov [wynik+4],dl

cdq
mov ebx,6
div ebx
add dl,'0'
mov [wynik+3],dl

cdq
mov ebx,24
div ebx
mov eax,edx
add eax,1

cdq
mov ebx, 10
div ebx
add dl,'0'
mov [wynik+1],dl
add al,'0'
mov [wynik],al

mov    eax, 4        ; zapis do pliku
mov    ebx, 1        ; na ekran
mov    ecx, wynik    ; napis do wyświetlenia: pytanie
mov    edx, dl_wyn    ; długość napisu
int    80h        ; wyświetlamy
    
koniec:    
    mov    eax, 1
    int 80h

section .data
    wynik  db "gg:mm:hh",13,10,0
    dl_wyn equ $- wynik

Zestaw 3 struktury kontrolne

Rozwiązania

Zadanie 1

%include "asm_io.inc"

section .data

prompt: db "Podaj dane",13,10,0
spacja: db " ",0
pierwsza: db "liczba jest pierwsza",0
nie_pierwsza: db "liczba nie jest pierwsza",0
;
; dane zainicjalizowane

;

section .bss
input1: resd 1
input2: resd 1
 
;
; dane niezainicjalizowane
;

section .text
global _asm_main
_asm_main:
enter 0,0 ; setup 
pusha

mov eax, prompt
call print_string

call read_int
mov [input1],eax
mov        ecx, [input1]        ; ECX to zmienna input1
mov ebx,0

petla_for:
    cmp        ecx,[input1]
    je koncowa_instrukcja_petli
    cmp ecx,1
    je koncowa_instrukcja_petli
    cmp ecx,0
    je wyjdz_za_petle
    
    mov        edx,0
    mov     eax,[input1]
    div        ecx
    cmp edx,0
    jne koncowa_instrukcja_petli
    inc ebx
koncowa_instrukcja_petli:
loop    petla_for            ; zmniejsz ECX o 1 i jeśli różny od

wyjdz_za_petle:
cmp ebx,0
jne koniec
mov eax,pierwsza
call print_string
jmp finisz
koniec:
mov eax,nie_pierwsza
call print_string

;
; Właściwy kod wstawiamy tu. 
; Nie należy modyfikować koduprzed i po tym komentarzu
;
finisz:
popa
mov eax, 0 ; powrót do C
leave
ret

Zadanie 2

%include "asm_io.inc"

section .data

prompt: db "Podaj dane",13,10,0
spacja: db " ",0
;
; dane zainicjalizowane

;

section .bss
input1: resd 1
input2: resd 1
 
;
; dane niezainicjalizowane
;

section .text
global _asm_main
_asm_main:
enter 0,0 ; setup 
pusha

mov eax, prompt
call print_string

call read_int
mov [input1],eax

mov        ecx, [input1]        ; ECX to zmienna input1

petla_for:
;    mov        eax, ecx
;    call print_int
;    mov eax,spacja
;    call print_string

    mov        edx,0
    mov     eax,[input1]
    div        ecx

    cmp edx,0
    jne koniec
    mov eax,ecx
    call print_int
    call print_nl
koniec:
loop    petla_for            ; zmniejsz ECX o 1 i jeśli różny od


;
; Właściwy kod wstawiamy tu. 
; Nie należy modyfikować koduprzed i po tym komentarzu
;

popa
mov eax, 0 ; powrót do C
leave
ret

Zadanie 3

%include "asm_io.inc"

section .data

prompt: db "Podaj dane",13,10,0
NWW: db "NWW = ",0
;
; dane zainicjalizowane

;

section .bss
input1: resd 1
input2: resd 1
 
;
; dane niezainicjalizowane
;

section .text
global _asm_main
_asm_main:
enter 0,0 ; setup 
pusha

mov eax, prompt
call print_string
call read_int
mov [input1],eax

mov eax, prompt
call print_string
call read_int
mov [input2],eax

mov    ecx, 1

petla_for:
    mov eax,[input1]
    mul ecx
;    mov ebx,[input2]
;    div ebx
    div dword [input2]
    cmp edx,0
    je finisz
    inc ecx
jmp petla_for

finisz:
    mov eax,[input1]
    mul ecx
    call print_int
    call print_nl


popa
mov eax, 0 ; powrót do C
leave
ret

Zadanie 4

; nasm -felf -o prime.obj prime.asm
; gcc -o driver.obj -c driver.c
; gcc -o prime.exe prime.obj driver.bj asm_io.obj
;


; Works like the following C program:
; #include <stdio.h>
;
;int main()
;{
;  unsigned guess;          /* current guess for prime      */
;  unsigned factor;         /* possible factor of guess     */
;  unsigned limit;          /* find primes up to this value */
;
;  printf("Find primes up to: ");
;  scanf("%u", &limit);
;
;  printf("2\n");    /* treat first two primes as special case */
;  printf("3\n");
;
;  guess = 5;        /* initial guess */
;  while ( guess <= limit ) {
;    /* look for a factor of guess */
;    factor = 3;
;    while ( factor*factor < guess && guess % factor != 0 )
;      factor += 2;
;    if ( guess % factor != 0 )
;      printf("%d\n", guess);
;    guess += 2;    /* only look at odd numbers */
;  }
;  return 0;
;}
;

%include "asm_io.inc"

segment .data
Message         db      "Find primes up to: ", '$'


segment .bss
Limit           resd    1               ; find primes up to this limit
Guess           resd    1               ; the current guess for prime

 

segment .text
        global  _asm_main
_asm_main:
        enter   0,0               ; setup routine
        pusha

        mov     eax,  Message
        call    print_string
        
        call    read_int             ; scanf("%u", & limit );
        mov     [Limit], eax

        mov     eax, 2               ; printf("2\n");
        call    print_int
        call    print_nl
        mov     eax, 3               ; printf("3\n");
        call    print_int
        call    print_nl

        mov     dword [Guess], 5     ; Guess = 5;

while_limit:                         ; while ( Guess <= Limit )
        mov     eax,[Guess]
        cmp     eax, [Limit]
        jnbe    end_while_limit      ; use jnbe since numbers are unsigned

        mov     ebx, 3               ; ebx is factor = 3;
while_factor:
        mov     eax,ebx
        mul     eax                  ; edx:eax = eax*eax
        jo      end_while_factor     ; if answer won't fit in eax alone
        cmp     eax, [Guess]
        jnb     end_while_factor     ; if !(factor*factor < guess)
        mov     eax,[Guess]
        mov     edx,0
        div     ebx                  ; edx = edx:eax % ebx
        cmp     edx, 0
        je      end_while_factor     ; if !(guess % factor != 0)

        add     ebx,2                ; factor += 2;
        jmp     while_factor
end_while_factor:
        je      end_if               ; if !(guess % factor != 0)
        mov     eax,[Guess]          ; printf("%u\n")
        call    print_int
        call    print_nl
end_if:
        mov     eax,[Guess]
        add     eax, 2
        mov     [Guess], eax         ; guess += 2
        jmp     while_limit
end_while_limit:

        popa
        mov     eax, 0            ; return back to C
        leave                     
        ret

Zestaw 4 tablice

Rozwiązania

Zadanie 1

%include "asm_io.inc"
;
; dane zainicjalizowane
section .data
prompt: db "Podaj dane",13,10,0
;

;
; dane niezainicjalizowane
section .bss
mojaTablica: resd 10
;

section .text
global _asm_main
_asm_main:
enter 0,0 ; setup
pusha

;
; Nie należy modyfikować kod w sekcji .text przed tym komentarzem
; Właściwy kod wstawiamy tu.

mov ecx,5
mov ebx,0
petla_for_czytanie:
    mov eax, prompt
    call print_string
    call read_int
    mov [mojaTablica+4*ebx],eax
    inc ebx
loop    petla_for_czytanie

call print_nl

mov ecx,5
mov ebx,0
petla_for_pisanie:
    mov eax,[mojaTablica+4*ebx]
    call print_int
    call print_nl
    inc ebx
loop petla_for_pisanie

; Nie należy modyfikować kod po tym komentarzu
;
popa
mov eax, 0 ; powrót do C
leave
ret

Zadanie 2

    section .text            
    global _start            
                  

    _start:
        mov    eax, 4            ; zapis do pliku
        mov    ebx, 1            ; na ekran
        mov    ecx, prompt       ; napis do wyświetlenia
        mov    edx, prompt_dl    ; długość napisu
        int    80h               ; wyświetlamy

        mov    eax, 3        
        mov    ebx, 0        
        mov    ecx, dane    
        mov    edx, dane_dl    
        int    80h        

        xor edi,edi
        mov edi,0
        mov ecx,dane+dane_dl
        petla_for:
            mov    eax, 4        
            mov    ebx, 1       
            mov    edx, 1     
            int    80h        
            dec    ecx
            inc     edi
            cmp     edi,dane_dl
        jle petla_for

        mov    eax, 4        
        mov    ebx, 1       
        mov     ecx, nl
        mov    edx, nl_dl     
        int    80h        

        mov    eax, 1
        xor    ebx, ebx
        int    80h


    section .data        

    prompt:    db    "Wprowadz dane ",13,10
    prompt_dl    equ    $ - prompt

    nl:    db    13,10
    nl_dl    equ    $ - nl

    
    dane:        times 20 db 0
    dane_dl        equ    $ - dane

Zadanie 3

Iterowanie po tablicy wczytanej z klawiatury - Windows

; wersja NASM: program zapisany w pliku tekstowym a.asm
; kompilacja: nasm -fbin -o a.com a.asm

org 0x100

section .data                            ; sekcja danych zainicjalizowanych
    info: db "Wprowadz ciag znakow",13, 10, '$'        ; ciąg znaków zakończony znakiem dolara - wymagane przez funkcję                                             ; o numerze 9, wyświetlającą ciąg, znaki 10 i 13 dają nową linię
    tekst1:   db 20        ; maksymalna liczba znaków do pobrania
            db 0        ; tu dostaniemy, ile znaków pobrano
            times 22 db "$"    ; miejsce na dane
    tekst2:  times 22 db "$"    ; miejsce na dane

section .text           ; sekcja kodu

    mov ah, 9
    mov dx, info
    int 0x21            ; wywołaj przerwanie 0x21 - po załadowaniu 9 do AH wyświetlona będzie
                        ; zawartość rejestru DX

    mov    ah, 0ah    ; funkcja pobierania danych z klawiatury
    mov    dx, tekst1    ; bufor na dane
    int    21h        ; pobierz dane

    mov cl,[tekst1+1]
    mov edx,0
    for:
        mov al,[tekst1+edx+2]
        sub al,'0'
        mov [tekst2+edx],al
        inc edx
    loop for

    mov    ah, 9
    mov    dx, tekst2
    int    21h        

    mov ax, 0x4C00      
                        
    int 0x21

Iterowanie po tablicy wczytanej z klawiatury - Linux

    section .text        
    global _start    
            

    _start:
    
        mov    eax, 4                    ; zapis do pliku
        mov    ebx, 1                    ; na ekran
        mov    ecx, prompt                ; napis do wyświetlenia: pytanie
        mov    edx, prompt_dl            ; długość napisu
        int    80h                    ; wyświetlamy

        mov    eax, 3                    ; czytanie z pliku
        mov    ebx, 0                    ; z klawiatury
        mov     ecx, dane1
        mov    edx, dane1_dl                ; ile bajtów czytać maksymalnie?
        int    80h                    ; wczytujemy

        dec     eax
        mov     [przeczytane_bajty1],eax    
        add    eax,'0'                ;ile bajtów przeczytano
        mov    [input],eax
        mov     ecx,input                ; wyświetlam dla testu
        mov    eax, 4                    ; zapis do pliku
        mov    ebx, 1                    ; na ekran
        mov    edx, 1                    ; długość napisu
        int    80h                    ; wyświetlamy

        mov    eax, 4                
        mov    ebx, 1                
        mov    ecx, nl        
        mov    edx, nl_dl    
        int    80h    

;
; sprawdzam poprawność danych - tylko cyfry
;
        xor    eax,eax
        mov     ebx,dane1
        mov     ecx,[przeczytane_bajty1]
        petla_for1:
            mov     al,[ebx]
            mov    ah,[testMAX]
            cmp    al,ah
            jg    err
            mov    ah,[testMIN]
            cmp    al,ah
            jl    err
            inc    ebx
        loop petla_for1

        jmp przeksztalc
err:
        mov    eax, 4        
        mov    ebx, 1        
        mov    ecx, zle_dane    
        mov    edx, zle_dane_dl    
        int    80h        
        jmp     _start

przeksztalc:

;
;    przekształcam tekst na liczbę
;
        xor    ebx,ebx
        xor    edx,edx
        mov    edx,1
        mov     ebx,0
        mov     ecx,dane1
        add    ecx,[przeczytane_bajty1]
        dec     ecx
        petla_liczba1:
            xor    eax,eax
            mov     al,[ecx]
            sub    al,'0'
            imul    eax,edx
            add    ebx,eax
            dec    ecx
            imul    edx,10
            cmp    ecx,dane1
        jge petla_liczba1
        mov    [liczba1],ebx

        mov    eax,[liczba2]            ;wpisana na stałe liczba 
        add    eax,[liczba1]

;
; przekształcam liczbę na tekst w odwrotnej kolejności cyfr
;
        cdq
        mov     edi,0
        petla_przepisz_wynik_dodwania_do_ciagu_znakow:
            mov    ecx,10d
            xor    edx,edx
            div    ecx
            add    dl,'0'
            mov    [dane2+edi],dl
            inc     edi
            imul    ecx,10d
            cmp    eax,0
        jne    petla_przepisz_wynik_dodwania_do_ciagu_znakow

;
; odwracam kolejność
;
        mov    ecx,0
        petla:
            mov    al,[dane2+edi]
            mov    [dane1+ecx],al
            inc    ecx
            dec    edi
            cmp    edi,0
        jge petla

        mov    eax, 4        
        mov    ebx, 1        
        mov    ecx, dane1    
        mov    edx, dane1_dl    
        int    80h        

        mov    eax, 4    
        mov    ebx, 1    
        mov    ecx, nl
        mov    edx, nl_dl    
        int    80h    

        mov    eax, 1
        xor    ebx, ebx
        int    80h


section .data    

    prompt:    db    "Wprowadz dane ",13,10
    prompt_dl    equ    $ - prompt

    nl:    db    13,10
    nl_dl    equ    $-nl

    dane1:        times 6 db 0
    dane1_dl        equ    $ - dane1
    dane2:        times 6 db 0
    dane2_dl        equ    $ - dane2

    zle_dane: db    "Zle dane",13,10
    zle_dane_dl    equ    $ - zle_dane

    przeczytane_bajty1:    dd    0
    przeczytane_bajty2:    dd    0
    input: dd    '0'

    testMIN: db    '0'
    testMAX: db    '9'

    liczba1: dd    0
    liczba2: dd    121d

Zadanie 4

    section .text        
    global _start    
            

    _start:
    
        mov    eax, 4                    ; zapis do pliku
        mov    ebx, 1                    ; na ekran
        mov    ecx, prompt                ; napis do wyświetlenia: pytanie
        mov    edx, prompt_dl            ; długość napisu
        int    80h                    ; wyświetlamy

        mov    eax, 3                    ; czytanie z pliku
        mov    ebx, 0                    ; z klawiatury
        mov     ecx, daneIN
        mov    edx, daneIN_dl                ; ile bajtów czytać maksymalnie?
        int    80h                    ; wczytujemy

        dec     eax
        mov     [przeczytane_bajty],eax    

        mov    ecx,daneIN
        mov    edx,0
        mov    edi,daneIN
        add    edi,[przeczytane_bajty]
        dec    edi
        koduj:
            mov    ebx,0
porownanie: mov    ah,[tablica1+ebx]
            mov    al,[ecx]
            cmp    al,' '
            je     spacja
            cmp    ah,al
            jne    not_equal
            mov    al,[tablica2+ebx]
spacja:     mov    [daneOUT+edx],al
not_equal:  inc    ebx
            cmp    ebx,25
            jle    porownanie
            inc    ecx
            inc    edx
            cmp    ecx,edi
        jle    koduj

        mov    eax, 4                
        mov    ecx,daneOUT
        mov    ebx, 1                
        mov    edx,daneOUT_dl
        int    80h

        mov    eax, 4                
        mov    ebx, 1                
        mov    ecx, nl        
        mov    edx, nl_dl    
        int    80h    

        jmp    _start

        mov    eax, 1
        xor    ebx, ebx
        int    80h


section .data    

    prompt:    db    "Podaj ciag znakow ",13,10
    prompt_dl    equ    $ - prompt

    nl:    db    13,10
    nl_dl    equ    $-nl

    daneIN:        times 256 db 0
    daneIN_dl        equ    $ - daneIN
    daneOUT:        times 256 db 0
    daneOUT_dl        equ    $ - daneOUT

    przeczytane_bajty:    dd    0

    tablica1:    db    "abcdefghijklmnopqrstuvwxyz"
    tablica2:    db    "zyxwvutsrqponmlkjihgfedcba"

Zestaw 5 stos

Rozwiązania

Zadanie 1

; nasm -felf -o first.obj first.asm
; nasm -felf -o asm_io.obj asm_io.asm
; gcc -o driver.obj -c driver.c
; gcc -o first.exe first.obj driver.obj asm_io.obj
;

%include "asm_io.inc"
;
; initialized data is put in the .data segment
;
segment .data
;
; These labels refer to strings used for output
;
prompt1: db    "Enter a number: ", 0
result:  db       "Result = ",0    
;
; uninitialized data is put in the .bss segment
;
segment .bss
;
; These labels refer to double words used to store the inputs
;
input1  resd 1
input2  resd 1

 

;
; code is put in the .text segment
;
segment .text
        global  _asm_main
_asm_main:
        enter   0,0               ; setup routine
        pusha

        mov     eax, prompt1      ; print out prompt
        call    print_string
        call     get_int
        mov        [input1],eax

        mov     eax, prompt1      ; print out prompt
        call    print_string
        call     get_int
        mov        [input2],eax

        mov     eax, result      ; print out prompt
        call    print_string
        
        mov     eax, [input1]     ; eax = dword at input1
        add     eax, [input2]     ; eax += dword at input2
        mov     ebx, eax          ; ebx = eax

        mov     eax, ebx
        call    print_int         ; print out sum (ebx)
        call    print_nl          ; print new-line

        popa
        mov     eax, 0            ; return back to C
        leave                     
        ret

get_int:
    call read_int
    ret

Zadanie 2

; wersja NASM: program zapisany w pliku tekstowym a.asm
; kompilacja: nasm -fbin -o a.com a.asm

org 0x100

section .data                            ; sekcja danych zainicjalizowanych
liczba1:    dd    1248
liczba2:    dd    2287

section .text           ; sekcja kodu

    mov eax, [liczba1]
    call pisz

    mov eax, [liczba2]
    call pisz
    
    mov ax, 0x4C00     
    int 0x21
    
pisz:
    mov     edi,0
    for1:
        mov        ecx,10d
        xor        edx,edx
        div        ecx
        add        dl,'0'
        push    edx
        inc        edi
        cmp        eax,0
    jne for1
    
    mov ecx,edi
    for2:
        pop edx
        mov    ah,02h
        int 21h
    loop for2

    mov dl,10
    mov    ah,02h
    int 21h
    mov dl,13
    mov    ah,02h
    int 21h
ret

Zadanie 3

; nasm -felf -o first.obj first.asm
; nasm -felf -o asm_io.obj asm_io.asm
; gcc -o driver.obj -c driver.c
; gcc -o first.exe first.obj driver.obj asm_io.obj
;

%include "asm_io.inc"

segment .data
Prompt: db "Podaj liczbe elementow ",0
Spacja: db " ",0

segment .bss
mojaTablica: resd 100
liczbaElementow: resd 1
minimum: resd 1


segment .text
        global  _asm_main
_asm_main:
        enter   0,0               ; setup routine
        pusha

        mov eax,Prompt
        call print_string
        
        call read_int
        dec eax
        mov [liczbaElementow],eax
        
        call czytajTablice

        call piszTablice
        
        mov ecx,0
        mainLoop:
            call min        ;w eax zwracam indeks minimalnego
            push dword[mojaTablica+4*ecx]
            mov ebx,[mojaTablica+4*eax]
            mov [mojaTablica+4*ecx],ebx
            pop ebx
            mov [mojaTablica+4*eax],ebx
                pusha
                    call piszTablice
                popa
            inc ecx
            cmp ecx,[liczbaElementow]
        jl mainLoop
        
        popa
        mov     eax, 0            ; return back to C
        leave                     
        ret

czytajTablice:
    mov ecx,0
    for1:
        call read_int
        mov [mojaTablica+4*ecx],eax
        inc ecx
        cmp ecx,[liczbaElementow]
    jle for1
ret

piszTablice:
    call print_nl
    mov ecx,0
    for2:
        mov eax,[mojaTablica+4*ecx]
        call print_int
        mov eax,Spacja
        call print_string
        inc ecx
        cmp ecx,[liczbaElementow]
    jle for2
    call print_nl
ret

min:
    mov eax,[mojaTablica]
    mov edx,0
    mov edi,ecx
    for3:
        mov ebx,[mojaTablica+4*edi]
        cmp eax,ebx
        jle next
        mov eax,ebx
        mov edx,edi
next:   inc edi
        cmp edi,[liczbaElementow]
    jle for3
    mov eax,edx
ret

Zadanie 4

To jest wariacja zadania 2 - dzielenie przez 16 lub 2 (może przesunięcia bitowe?)

Zestaw 6 ASM + C

Rozwiązania

Zadania 1-3

Listing 4 - driver do zadań 1 - 3

/*
Kompilacja dla Win
nasm -fcoff casm1.asm 
nasm -fcoff sumujN.asm 
nasm -fcoff sumujWektor.asm 
nasm -fcoff sumujWektor1.asm 
nasm -fcoff minmax.asm 
gcc -c casm.c
gcc casm.o casm1.o sumujN.o sumujWektor.o sumujWektor1.o minmax.o -o cams1.exe
*/

    #include <stdio.h>
    #include <stdlib.h>
    
    extern int _suma (int a, int b); /* deklaracja funkcji zewnętrznej */
    extern int _sumujN (int N); /* deklaracja funkcji zewnętrznej */
    extern int _sumujWektor(int *wektor, int N); /* deklaracja funkcji zewnętrznej */
    extern void _sumujWektor1(int N,int *wektor,int *suma);
    extern void _minmax(int N,int *wektor,int *min);
    
    int suma (int a, int b);     /* prototyp funkcji */
    int sumujN(int N);
    int sumujWektor(int *wektor,int N);
    void sumujWektor1(int N,int *wektor,int *suma);
    void minmax(int N,int *wektor,int *min,int *max);
    
    int main()
    {
        int c, d, N ,i, min, max, sum;
        int *wektor;

        printf("Podaj dwie liczby: ");
        scanf("%d %d",&c,&d);
        printf("%d\n", suma(c,d));

        printf("Podaj N: ");
        scanf("%d",&N);
        printf("suma od 1 do %d = %d\n",N,sumujN(N));
        

        printf("Podaj ilosc elementow wektora: ");
        scanf("%d",&N);
        wektor=(int *)calloc(N,sizeof(int));
        for(i=1;i<=N;i++)
        {
            printf("podaj %d z %d element wektora: ",i,N);
            scanf("%d",&wektor[i-1]);
        }
        printf("suma elementow wektora = %d\n",sumujWektor(wektor,N));


        printf("Podaj ilosc elementow wektora: ");
        scanf("%d",&N);
        wektor=(int *)realloc(wektor,N*sizeof(int));
        for(i=1;i<=N;i++)
        {
            printf("podaj %d z %d element wektora: ",i,N);
            scanf("%d",&wektor[i-1]);
        }
        sumujWektor1(N,wektor,&sum);
        minmax(N,wektor,&min,&max);
        printf("sum = %d, min = %d, max = %d\n",sum,min,max);
        
        return 0;
    }

Listing 5 - sumowanie dwóch liczb

    section .text

    global    _suma

    _suma:
    ; po wykonaniu push ebp i mov ebp, esp:
    ; w [ebp]    znajduje się stary EBP
    ; w [ebp+4]  znajduje się adres powrotny z procedury
    ; w [ebp+8]  znajduje się pierwszy parametr,
    ; w [ebp+12] znajduje się drugi parametr
    ; itd.

    %idefine    a    [ebp+8]
    %idefine    b    [ebp+12]

        push    ebp
        mov    ebp, esp

        mov    eax, a
        add    eax, b

    ; LEAVE = mov esp, ebp / pop ebp
        leave
        ret

Listing 6 - sumowanie liczb od 1 do N

    section .text

    global    _sumujN

    _sumujN:

    push    ebp        ;tego nie ruszac
    mov    ebp, esp    ;tego nie ruszac

    ; stad zaczyna sie kod uzytkownika
    
    %idefine    N    [ebp+8]

    mov        eax, 0
    mov     ecx,N
    for:
        add     eax,ecx
    loop for

    ;to konczy sie kod uzytkownika
    leave
    ret

Listing 7 - sumowanie elementów wektora - funkcja zwraca wartość

    section .text

    global    _sumujWektor

    _sumujWektor:
    push    ebp        ;tego nie ruszac
    mov    ebp, esp    ;tego nie ruszac

    ; stad zaczyna sie kod uzytkownika
    
    mov        eax, 0
    mov        ecx, [ebp+12]
    mov        edx, [ebp+8]
    for:
        add     eax, [edx+4*ecx-4]
    loop for

    ;to konczy sie kod uzytkownika
    leave
    ret

Listing 8 - sumowanie elementów wektora - wynik zwracany przez wskaźnik

segment .text
global _sumujWektor1

_sumujWektor1:

    enter 4,0
    push ebx

    mov dword[ebp-4],0

    mov        ecx, [ebp+8]
    mov        edx, [ebp+12]
    for:
        mov     ebx,[edx+4*ecx-4]
        add     [ebp-4], ebx
    loop for

    mov ebx, [ebp+16] ; ebx = sump
    mov eax, [ebp-4] ; eax = sum
    mov [ebx], eax
    
pop ebx ; restore ebx
leave
ret    

Listing 8 - min i max spośród elementów wektora - wyniki zwracane przez wskaźniki

segment .text
global _minmax

_minmax:

    enter 8,0                    ;rezerwuje miejsce na dwie zmienne typu int
    push ebx                    ;konwencja

    mov        ecx, [ebp+8]        ;przekazuje N
    mov        edx, [ebp+12]        ;przekazuje adres tablicy
    mov     eax,[edx]            ;pierwszy element tablicy do eax
    mov     [ebp-4],eax            ;do tymczasowej zmiennej przekazuje pierwszy element tablicy
    mov     [ebp-8],eax            ;do tymczasowej zmiennej przekazuje pierwszy element tablicy
    for:
        mov     ebx,[edx+4*ecx-4]
        cmp     [ebp-4], ebx
        jle     next1
        mov        [ebp-4], ebx
next1:    
        cmp        [ebp-8], ebx
        jge        next2
        mov        [ebp-8], ebx
next2:
    loop for

    mov ebx, [ebp+16]         ; ebx = minp - wskaznik do wyniku
    mov eax, [ebp-4]         ; eax = min
    mov [ebx], eax

    mov ebx, [ebp+20]         ; ebx = maxp - wskaznik do wyniku
    mov eax, [ebp-8]         ; eax = max
    mov [ebx], eax
    
pop ebx                     ; odzyskuje ebx
leave
ret    

Zadanie 4

Listing 9 - driver

    #include <stdio.h>

    extern int _factorial (int a); /* deklaracja funkcji zewnętrznej */

    int factorial (int a);     /* prototyp funkcji */

    
    int main()
    {
        int c=1;
        scanf("%d",&c);
        printf("%d\n", factorial(c));
        return 0;
    }

Listing 10 - silnia - wersja 1

; factorial.asm
;
; Illustration of a recursive function.
; ----------------------------------------------------------------------------  

        global _factorial
        
        section .text
_factorial:
        mov     eax, [esp+4]            ; n
        cmp     eax, 1                  ; n <= 1
        jnle    L1                      ; if not, go do a recursive call
        mov     eax, 1                  ; otherwise return 1
        jmp     L2
L1:
        dec     eax                     ; n-1
        push    eax                     ; push argument
        call    _factorial              ; do the call, result goes in eax
        add     esp, 4                  ; get rid of argument
        imul    eax, [esp+4]            ; n * factorial(n-1)
L2:
        ret

Listing 11 - silnia - wersja 2

; finds n!
segment .text
global _factorial

 _factorial:
 enter 0,0

 mov eax, [ebp+8] ; eax = n
 cmp eax, 1
 jbe term_cond ; if n <= 1, terminate
 dec eax
 push eax
 call _factorial ; eax = fact(n-1)
 ;pop ecx ; answer in eax
 mul dword [ebp+8] ; edx:eax = eax * [ebp+8]
 jmp short end_fact
 term_cond:
 mov eax, 1
 end_fact:
 leave
 ret


Wyszukiwarka