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