Miłosz Grzegorzewski
description
Transcript of Miłosz Grzegorzewski
Witaj świecie dla różnych kompilatorów (NASM, FASM, Gnu As). Assembler - różnice w składni
Intel i AT&T.
Miłosz Grzegorzewski
Agenda
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.
NASMNetwide 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 – hello world na windowsieorg 100h
%define cr 13%define lf 10%define nwln cr, lf
section .dataHelloWorld db "Hello World!", nwln, '$'
section .textglobal _start
_start:mov ah, 9mov dx, HelloWorldint 21hmov ax, 4C00hint 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 .dataHelloWorld 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 windowsiemov ah, 9
mov dx, HelloWorldint 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, 4C00hint 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 linuxiesegment .datamsg 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 linuksie
Kompilacja:nasm -f elf hello.asm
Linkowanie do postaci wykonywalnej:ld hello.o -o hello
Uruchomienie:./hello
FASMFASM – 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 – hello world na windowsie
format MZentry .code:startsegment .codestart:
mov ax, .datamov ds, axmov dx, msgmov ah, 9hint 21hmov ah, 4chint 21h
segment .datamsg 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
dsmov 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, 4chint 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 w systemie linuxformat 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, tekstmov eax, 4mov ebx, 1
mov edx, 13int 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, 1dec ebxint 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
GNU Assembler
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 – hello world w systemie Linux
.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.datanapis: .string "hello world!\n"len =. - napis
GNU Asembler – 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 Windows
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
Assembler - różnice w składni Intel i AT&T
1. Odnoszenie się do rejestrów
AT&T: % eaxIntel: 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 standardIntel: 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, %ebxIntel: 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, %bxIntel: 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: _boogaIntel: [_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+8Prawdopodobnie można to również wykonać w składni intelaIntel: [_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]
Dziękuje za uwagę :)