-
Notifications
You must be signed in to change notification settings - Fork 6
/
asm.txt
430 lines (359 loc) · 11.9 KB
/
asm.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
_____ ___. .__
/ _ \ ______ ______ ____ _____\_ |__ | | ___________
/ /_\ \ / ___// ___// __ \ / \| __ \| | _/ __ \_ __ \
/ | \\___ \ \___ \\ ___/| Y Y \ \_\ \ |_\ ___/| | \/
\____|__ /____ >____ >\___ >__|_| /___ /____/\___ >__|
. \/ \/ \/ \/ \/ \/ \/
Proč assembler?
---------------
1. Větší efektivita využití CPU
2. Rychlejší (a predikovatelné) přerušovací rutiny
3. Efektivita při práci s pamětí (cache+RAM)
4. Kompaktní kód
Některé požadavky se mohou vzájemně vylučovat!
(Lepší pochopení práce s gdb a dalšími debuggery)
Role assembleru
---------------
▶ Několik úrovní abstrakce (vrstev nad HW)
5 uživatelské aplikace
4½ (skriptovací engine)
4 vyšší programovací jazyk
3 assembler
2 strojový kód
1 syscalls
0 HW
Závislost na platformě
----------------------
5 uživatelské aplikace
4½ (skriptovací engine)
4 vyšší programovací jazyk
↑↑↑ nezávislý ↑↑↑
↓↓↓ závislý ↓↓↓
3 assembler
2 strojový kód
1 syscalls
0 HW
Použití assembleru v minulosti
------------------------------
▶ První generace mainframů
- vývojové diagramy v roli „vyššího jazyka“
- assembler
- strojový kód (zpočátku ruční překlad!)
▶ Mainframy a později minipočítače
- přechod k vyšším programovacím jazykům
- levnější vývoj, šance na přenositelnost
▶ Osmibitové herní konzole
- assembler jediná rozumná volba
▶ Domácí mikropočítače
- návrat „ke kořenům“
- prakticky jediná volba pro profesionální aplikace
▶ Osobní mikropočítače
- Motorola 68000
- 8086/80286...
- specifické použití assembleru (hry, dema, ...)
▶ DSP
- výpočetní subrutiny (FFT...)
- přerušovací rutiny
Použití assembleru v současnosti
--------------------------------
1. Firmware
2. Kód pracující přímo s HW (senzory, CPU+FPGA)
3. DSP a MCU - rychlé přerušovací rutiny!
4. Instrukce nedostupné ve vyšším programovacím jazyce
5. Specifické subrutiny (SIMD, SSE, rotace, hledání vzorků...)
6. Zpracování signálů
7. Kodeky
8. Virtuální stroje generující strojový kód
9. Reverse engineering :-)
10. Samomodifikující se kód
11. DSP
12. Fingerprints (A86)
Instrukce nedostupné ve vyšším programovacím jazyce
---------------------------------------------------
▶ GCC nabízí ve formě „builtins“
__builtin_clz
__builtin_parity
__builtin_bswap64
a desítky dalších
Použití assembleru v současnosti
--------------------------------
▶ Většinou velmi SPECIFICKÉ pro určitou oblast
▶ Naprostá většina aplikací není psána pouze v assembleru
Coreboot: většinou C, jen zhruba 1% asm
Důvod: výhody vyšších programovacích jazyků + snadnější audit kódu
Příklad
-------
x264 naprogramovaný v assembleru
http://git.videolan.org/?p=x264.git;a=tree;f=common/x86;hb=HEAD
Hodnocení „popularity“ assembleru ½
-----------------------------------
OpenHub
cca 0,5% projektů, <0,2% commitů
Hodnocení „popularity“ assembleru
---------------------------------
TIOBE index
02/2017 02/2016 Jazyk Hodnocení Změna
1 1 Java 16,6% -4,4%
2 2 C 8,4% -7,1%
3 3 C++ 5,4% -1,4%
4 4 C# 4,9% +0,5%
5 5 Python 4,0% -0,1%
6 6 PHP 3,0% +0,3%
7 9 JavaScript 2,8% +0,6%
8 7 Visual Basic .NET 2,8% +0,3%
9 10 Delphi/Object Pascal 2,4% +0,3%
10 8 Perl 2,1% -0,0%
11 11 Ruby 2,1% +0,1%
12 16 Swift 2,1% +0,7%
13 13 Assembler ******** 2,1% +0,3%
Kdy/proč psát v assembleru
--------------------------
▶ Seřazeno podle důležitosti a podle specificity
1. Použití lepšího algoritmu (vyšší programovací jazyk)
čas/použití paměti
2. Použití překladače, ne intepretru (či mixu typu JVM)
3. Optimalizace nabízené překladačem + jejich kombinace
některé optimalizace se ovšem částečně vylučují (-Os, -O3)
4. Hinty pro překladač (nutno odzkoušet, zda mají význam)
const, const *, register
5. Profilování (!)
6. Speciální vlastnosti konkrétního překladače (nepřenositelné!)
__builtin_expect, __builtin_unreachable, __builtin_prefetch...
"hot" atribut u funkcí, "pure" atribut, "simd" apod.
https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
6. Přepis RELEVANTÍHO kódu do assembleru
Assembler a Linux
-----------------
▶ as (GNU Assembler, GAS)
▶ NASM (Netwide Assembler)
▶ Yasm
▶ FASM (flat assembler)
GNU Assembler
-------------
▶ Součást klasického toolchainu
cpp → gcc → as → ld → spustitelný_soubor
▶ Překlad do asm: gcc -S source.c
▶ Původně jen AT&T syntaxe
▶ Dnes i „Intel“ syntaxe (na x86/x86-64)
▶ Různý způsob zápisu podle platformy!
Jména registrů
Konstanty
Adresování
Komentáře
NASM
----
▶ Netwide Assembler
Syntaxe inspirována TASM a MASM
▶ Původní autor Simon Tatham (PuTTY...)
▶ Generuje objektový kód pro platformu x86 (16bit, 32bit, 64bit)
Zjednodušený toolchain
nasm → flat file (.COM, bootloader...)
nasm → ln → spustitelný_soubor
FASM
----
▶ Flat Assembler
▶ Tomasz Grysztar
▶ Backend pro PureBasic, BlitzMax a HLA
Syscally a GNU Assembler
------------------------
Ukončení procesu funkcí "exit"
▶ i386, syntaxe AT&T
▶ i386, syntaxe Intel
▶ ARM (32bit)
▶ AArch64
Syscally a GNU Assembler
------------------------
Kostra programu v assembleru
----------------------------
# Linux kernel system call table
sys_exit=1
.section .text
.global _start # tento symbol ma byt dostupny i linkeru
_start:
movl $sys_exit,%eax # cislo sycallu pro funkci "exit"
movl $0,%ebx # exit code = 0
int $0x80 # volani Linuxoveho kernelu
# Linux kernel system call table
sys_exit=60
.section .text
.global _start # tento symbol ma byt dostupny i linkeru
_start:
movl $sys_exit,%eax # cislo sycallu pro funkci "exit"
movl $0,%edi # exit code = 0
syscall # volani Linuxoveho kernelu
„Hello world“ v assembleru
--------------------------
# Linux kernel system call table
sys_exit=1
sys_write=4
.section .data
hello_lbl:
.string "Hello World!\n"
.section .text
.global _start # tento symbol ma byt dostupny i linkeru
_start:
mov $sys_write, %eax # cislo syscallu pro funkci "write"
mov $1,%ebx # standardni vystup
mov $hello_lbl,%ecx # adresa retezce, ktery se ma vytisknout
mov $13,%edx # pocet znaku, ktere se maji vytisknout
int $0x80 # volani Linuxoveho kernelu
movl $sys_exit,%eax # cislo sycallu pro funkci "exit"
movl $0,%ebx # exit code = 0
int $0x80 # volani Linuxoveho kernelu
Volání funkcí ze standardní céčkové knihovny
--------------------------------------------
puts
----
.intel_syntax noprefix
.section .data
hello_world_message:
.asciz "Hello world!\n" # zprava, ktera se ma vytisknout na standardni vystup
.section .text
.global main # tento symbol ma byt dostupny i linkeru
main:
sub rsp, 8 # zajistit zarovnani RSP na adresu delitelnou 16
# jedinym parametrem je adresa zpravy
mov rdi, offset hello_world_message
call puts # volani funkce 'puts' ze standardni knihovny
add rsp, 8 # obnoveni puvodni hodnoty RSP
xor eax, eax # navratova hodnota (exit status)
ret # ukonceni aplikace
printf
------
.intel_syntax noprefix
.section .data
hello_world_message:
.asciz "Hello world!\n" # zprava, ktera se ma vytisknout na standardni vystup
.section .text
.global main # tento symbol ma byt dostupny i linkeru
main:
sub rsp, 8 # zajistit zarovnani RSP na adresu delitelnou 16
# jedinym parametrem je adresa zpravy
mov rdi, offset hello_world_message
xor al, al # pocet parametru predanych ve vektorovych registrech
call printf # volani funkce 'printf' ze standardni knihovny
add rsp, 8 # obnoveni puvodni hodnoty RSP
xor eax, eax # navratova hodnota (exit status)
ret # ukonceni aplikace
Assembler v C
-------------
▶ Podporováno většinou překladačů
Ovšem není součástí standardu
▶ Blok nebo „makro“ asm popř. __asm__
asm {
add RAX, RBX
nop
}
asm("add RAX, RBX \n\t"
"nop");
Zápis v GCC
-----------
int main()
{
__asm__ __volatile__(
"nop \n\t"
: /* zadne vystupni registry */
: /* zadne vstupni operandy */
: /* zadne registry pouzivane uvnitr kodu */
);
return 0;
}
Specifikace výstupních operandů
-------------------------------
Explicitní registry pro výstupní operandy
-----------------------------------------
a → %rax, %eax, %ax, %al
b → %rbx, %ebx, %bx, %bl
c → %rcx, %ecx, %cx, %cl
d → %rdx, %edx, %dx, %dl
S → %rsi, %esi, %si
D → %rdi, %edi, %di
Specifikace vstupních operandů
------------------------------
Explicitní určení registru pro výstupní operand
-----------------------------------------------
Vliv optimalizací na generovaný kód
-----------------------------------
Použití syntaxe používané firmou Intel
--------------------------------------
Assembler a C pro procesory ARM
--------------------------------
gdb
---
▶ CLI
Ovládán interaktivně
Popř. lze spustit i skript s příkazy pro gdb
▶ TUI
gdbtui
Velké možnosti nastavení
Použití
Původně pro GNU CC
Compiler Collections
Dnes různé nástavby
Python...
Ladicí informace ve vytvářených programech
------------------------------------------
▶ gcc -g -O0 test.c
-g
přidání ladicích informací (symbolů)
-O0
vypnutí optimalizací (usnadní ladění)
Spuštění gdb
------------
▶ Tři základní metody
gdb program_name
gdb program_name PID
gdb program_name core
Základní příkazy
----------------
r run
start start+zastaví na mian
c cont continue
s step step into
n next step over
bt backtrace print stacktrace
l list výpis zdrojového kódu (fce)
p print výpis výrazu
q quit
h help
Breakpointy
-----------
b breakpoint na aktuálním řádku
b# breakpoint na řádku #
b fce breakpoint na funkci
b file:fce specifikace souboru s funkcí
b file:# specifikace souboru a čísla řádku
info b informace o všech breakpointech
delete # vymazání breakpointu s daným indexem
Breakpointy s podmínkou
-----------------------
b fce if cond
cond může být například x<10
ignore # count
# je index (číslo) breakpointu
count je počet opakování
Watchpointy
-----------
watch expr
zastaveno při zápisu
rwatch expr
zastaveno při čtení
awatch expr
watch+rwatch
info watchpoints
Demo
----
▶ as -g hello_world.s -o hello_world.o
▶ ld hello_world.o -o hello_world
▶ gdb hello_world
b _start
display $eax
display $ebx
r
Breakpoint 1, _start () at hello_world.s:32
2: $ebx = 0
1: $eax = 0
n
2: $ebx = 0
1: $eax = 4
c