430 likes | 561 Views
Miłosz Grzegorzewski. Witaj świecie dla różnych kompilatorów (NASM, FASM, Gnu As). Assembler - różnice w składni Intel i AT&T. 1. Opis NASM oraz „Hello world” 2. Opis FASM oraz „Hello world” 3. Opis GNU Assembler oraz „Hello world” 4. Różnice w składni Intela i AT&T. Agenda.
E N D
Miłosz Grzegorzewski Witaj świecie dla różnych kompilatorów (NASM, FASM, Gnu As). Assembler - różnice w składni Intel i AT&T.
1. Opis NASM oraz „Hello world” 2. Opis FASM oraz „Hello world” 3. Opis GNU Assembler oraz „Hello world” 4. Różnice w składni Intela i AT&T. Agenda
Netwide Assembler to wolnodostępny asembler dla języka Asembler x86. Został stworzony przez Simona Tathama jako alternatywa dla GNU Assembler z pakietu binutils, który został zaprojektowany jako back-end dla kompilatorów, w związku z czym nie posiada odpowiedniego interfejsu użytkownika. Obecnie NASM rozwijany jest w ramach SourceForge. Składnia języka używana przez NASM jest składnią Intela z niewielkimi modyfikacjami. NASM jest dostępny na zasadach GNU General Public License oraz na własnej licencji. NASM
org 100h %define cr 13 %define lf 10 %define nwln cr, lf section .data HelloWorld db "Hello World!", nwln, '$' section .text global _start _start: mov ah, 9 mov dx, HelloWorld int 21h mov ax, 4C00h int 21h NASM – hello world na windowsie
org 100h ;określa gdzie dany program oczekuje, że zostanie załadowany do pamięci NASM – hello world na windowsie
section .data HelloWorld db "Hello World!", nwln, '$' segment o nazwie ".data". tekst to nazwa naszej zmiennej, db to typ naszej zmiennej (db - 1 bajt) nwln ; to wartość początkowa dla naszej zmiennej. znakiem $ ; oznaczamy koniec naszego ciągu (dla migrantów z C/C++ - jest to odpowiednik znaku '\0'). NASM – hello world na windowsie
mov ah, 9 mov dx, HelloWorld int 21h Instrukcja int wywołuje podprogram obsługi przerwania o podanym numerze . Podprogram ów wywołuje odpowiednią funkcję o numerze podanym w rejestrze ah (wcześniej nadaliśmy temu rejestrowi wartość 9, więc instrukcja int 21h wywołała funkcję numer 9 przerwania numer 21 w zapisie szesnastkowym). Wywołana w tym przypadku funkcja wyświetla w konsoli ciąg znaków, ;którego adres znajduje w rejestrze dx NASM – hello world na windowsie
mov ax, 4C00h int 21h Wychodzimy z programu, wywołujemy funkcję przerwania 21 o numerze 4C00h. Odpowiada ona za zakończenie działania programu i oddanie sterowania do systemu. NASM – hello world na windowsie
Kompilacja: nasm plik_asembler.asm -o plik_wynikowy NASM – hello world na windowsie
segment .data msg db "Hello World!", 0Ah ; umieszcza w segmencie danych ; ciąg znaków zakończony znakiem końca linii segment .text global _start _start: mov eax, 4 mov ebx, 1 mov ecx, msg ; adres pierwszego znaku do wyświetlenia mov edx, 14 ; liczba znaków do wyświetlenia int 80h ; wywołanie funkcji systemowej wyświetlającej ciąg ; znaków o danej długości ; wyjscie z programu mov eax, 1 xor ebx, ebx int 0x80 ; KONIEC PROGRAMU NASM – hello world na linuxie
Kompilacja: nasm -f elf hello.asm Linkowanie do postaci wykonywalnej: ld hello.o -o hello Uruchomienie: ./hello NASM – hello world na linuksie
FASM – flat assembler – szybki i wydajny asembler dla systemów: DOS, Windows oraz kompatybilnych z Uniksem (Linux, BSD). Opracowany przez Tomasza Grysztara. Program darmowy i wolnym, oparty o licencję BSD z zastrzeżeniem, że nie może być zmieniona na inną (np. GNU GPL – formalnie licencja BSD nie stawia takiego wymogu). Obsługuje wszystkie instrukcje procesorów 8080-80486/Pentium wraz z rozszerzeniami MMX, 3DNow!, SSE, SSE2, SSE3, SSSE3, SSE4, AVX, XOP oraz AVX2. Ponadto rozpoznaje instrukcje ze zbiorów VMX, SVM, SMX, XSAVE, RDRAND, FSGSBASE, INVPCID, HLE, RTM. Generuje kod w architekturze 16-bitowej, 32-bitowej i 64-bitowej (zarówno AMD64 i EM64T). Używa składni intela. FASM
format MZ entry .code:start segment .code start: mov ax, .data mov ds, ax mov dx, msg mov ah, 9h int 21h mov ah, 4ch int 21h segment .data msg db 'Hello World on FASM', '$' FASM – hello world na windowsie
format MZ ;potrzebne aby program uruchomić w systemie DOS segment .code ;nasm: .text segment .data msg db 'Hello World on FASM', '$' ;segment danych ;$ - znak zakonczenia zmiennej FASM – hello world na windowsie
mov ax, .data mov ds, ax ; zaladowanie ax do segmentu danych ds mov dx, msg ; zaladowanie msg do dx ( offsetu) mov ah, 9h ;należy wskazać poprawnie gdzie jest ;segment danych i jaki jest offsetu, ;zanim będzie można korzystać z int 21h, ;funkcja 9. int 21h ;Instrukcja int wywołuje podprogram ;obsługi przerwania o podanym numerze FASM – hello world na windowsie
mov ah, 4ch int 21h ;wywołanie funkcji przerwania 21 o numerze 4ch. ;Czyli zakończenie działania programu i oddanie sterowania ;do systemu. FASM – hello world na windowsie
Kompilacja: fasm plik_źródłowy.asm plik_wynikowy.exe FASM – hello world na windowsie
format ELF entry .text:_start segment .data tekst db "Hello World!\n" segment .text _start: xor ebx, ebx mov ecx, tekst mov eax, 4 inc ebx mov edx, 13 int 80H mov eax, 1 xor ebx, ebx int 80H FASM – hello world w systemie linux
format ELF ;Informuje asembler, że ma utworzyć linuxowy plik wykonywalny ELF. segment .data tekst db "Hello World!\n" ;Tworzy wewnątrz obecnie definiowanego segmentu (tj. segmentu .data) ciąg "Hello World" zakończony znakiem nowej linii. xor ebx, ebx ;zeruje rejestr ebx FASM – hello world w systemie linux
mov ecx, tekst mov eax, 4 mov ebx, 1 mov edx, 13 int 80h Instrukcja int wywołuje podprogram obsługi przerwania o podanym numerze. Podprogram ów wywołuje odpowiednią funkcję o numerze podanym w rejestrze eax. Wywołana w tym przypadku funkcja wyświetla w konsoli ciąg znaków, którego adres znajduje w rejestrze ecx do napotkania znaku o numerze w rejestrze edx. W efekcie na ekranie pojawi się więc napis Hello World!. Uwaga: należy zaznaczyć, że przerwanie 80h oraz opisana funkcja obsługiwane są przez Unix, przez co kod nie jest przenośny na inne platformy niż Linux. FASM – hello world w systemie linux
mov eax, 1 dec ebx int 80h Wywołuje funkcję przerwania 80 o numerze 1. Odpowiada ona za zakończenie działania programu i oddanie sterowania do systemu za pomocą kodu wyjścia w rejestrze EBX (instrukcja dec zmniejsza wartość o 1, przez co ebx jest teraz równy 0). FASM – hello world w systemie linux
Kompilacja i utworzenie obiektu wykonywalnego ELF: fasm prog.asm prog FASM – hello world w systemie linux
GNU Assembler (GAS) – darmowy i otwarto źródłowy asembler tworzony przez Projekt GNU. Jest on domyślnym back-endem GCC, jak i częścią pakietu GNU Binutils. GAS używa składni AT&T, ale od wersji 2.10 można ją zmienić na składnie Intela dodając na początku pliku linijkę .intel_syntax. GNU Assembler
.text ;kod programu .global _start _start: movl $4, %eax movl $1, %ebx movl $napis, %ecx movl $len, %edx int $0x80 movl $1, %eax movl $0, %ebx int $0x80 .data napis: .string "hello world!\n" len =. - napis GNU Assembler – hello world w systemie Linux
movl $4, %eax movl $1, %ebx movl $napis, %ecx movl $len, %edx int $0x80 Instrukcja mov (l na końcu to informacja, że zapisujemy dane do 32-bitowego rejestru) przenosi dane do odpowiednich rejestrów - w EAX znajdzie się numer funkcji systemowej (4 - write), EBX - plik docelowy (1 - standardowe wyjście), w ECX - adres, pod którym znajdują się dane do wyświetlenia oraz EDX - długość napisu. Instrukcja int powoduje wywołanie przerwania i realizację przez system operacyjny odpowiedniej czynności - w tym przypadku wypisanie na ekran "Hello world!". GNU Asembler – hello world w systemie Linux
movl $1, %eax movl $0, %ebx int $0x80 Tym razem wywołamy funkcję exit, której argumentem będzie 0. W ten sposób "poprosimy" system operacyjny o zakończenie pracy programu. GNU Asembler – hello world w systemie Linux
len = . - napis Jest to zmienna, która zawiera długość napisu. Kropka oznacza "aktualny adres" w pamięci (w naszym przypadku koniec napisu), a "napis" - adres etykiety, pod którą zawarto początek napisu. Różnica koniec - początek daje długość napisu, która jest niezbędna, aby program wypisał na ekranie dokładnie tyle znaków, ile liczy sobie napis. GNU Asembler – hello world w systemie Linux
Kompilacja: as hello.s -o hello.o Tak otrzymany kod wynikowy, musimy poddać działaniu linkera ld: ld hello.o -o hello Uruchomienie: ./hello GNU Asembler – hello world w systemie Linux
Analogiczny program, który kompiluje się pod systemem DOS(będąc emulowanym pod Windowsem) mógłby wyglądać np. tak: .data napis: .string "Hello World!\n$" .text .globl _start _start: movw $napis, %dx movb $9, %ah int $0x21 movw $0x4C00, %ax int $0x21 GNU Asembler – hello world w systemie Windows
1. Odnoszenie się do rejestrów AT&T: % eax Intel: eax Assembler - różnice w składni Intel i AT&T
2. Kolejność zapisu źródło/cel – zapisanie wartości rejestru eax do rejestru ebx AT&T: movl %eax, %ebx ;UNIX standard Intel: mov ebx, eax Assembler - różnice w składni Intel i AT&T
3. Załadowanie do rejestru wartości stałej/zmiennej - "$" AT&T: movl $0xd00d, %ebx Intel: mov ebx, d00dh Assembler - różnice w składni Intel i AT&T
4. Określanie rozmiaru operatora – składnia AT&T wymaga podania rozmiaru operatora (byte,word,longword), w przeciwnym razie będzie „zgadywać” czego lepiej unikać. AT&T: movw %ax, %bx Intel: mov bx, ax Assembler - różnice w składni Intel i AT&T
5. Intel posiada równoważne formy określania rozmiaru operatora takie jak: byte ptr, word ptr i dword ptr, jednak używane tylko w sytuacji odwoływania się do pamięci. Podstawowy format adresowania 32 bitowego AT&T: immed32(basepointer,indexpointer,indexscale) Intel: [basepointer + indexpointer*indexscale + immed32] Assembler - różnice w składni Intel i AT&T
6. Formy adresowania Assembler - różnice w składni Intel i AT&T
a) adresowanie poszczególnych zmiennych statycznych AT&T: _booga Intel: [_booga] „_” jest sposobem dostępu do zmiennych statycznych globalnych. Assembler - różnice w składni Intel i AT&T
b) adresowanie pośrednie AT&T: (%eax) Intel: [eax] Assembler - różnice w składni Intel i AT&T
c) Addressing a variable offset by a value in a register AT&T: _variable(%eax) Intel: [eax + _variable] Assembler - różnice w składni Intel i AT&T
d) Addressing a value in an array of integers (scaling up by 4) AT&T: _array(,%eax,4) Intel: [eax*4 + array] Assembler - różnice w składni Intel i AT&T
e) Adresowanie pooprzez przesunięcia o natychmiastową wartośc: AT&T: 1(%eax) Intel: [eax + 1] Assembler - różnice w składni Intel i AT&T
f) Można również wykonać proste działanie matemtyczne na zmiennej dynamicznej: AT&T: _struct_pointer+8 Prawdopodobnie można to również wykonać w składni intela Intel: [_struct_pointer]+8 Assembler - różnice w składni Intel i AT&T
g) Addressing a particular char in an array of 8-character records: eax holds the number of the record desired. ebx has the wanted char's offset within the record. AT&T: _array(%ebx,%eax,8) Intel: [ebx + eax*8 + _array] Assembler - różnice w składni Intel i AT&T