Po pierwsze, gcc
nie zawsze to robi. Wyściółka jest kontrolowana przez -falign-functions
, która jest automatycznie włączona -O2
i -O3
:
-falign-functions
-falign-functions=n
wyrównać początek funkcji do następnej power-of-two większa niż n
, omijając w górę do n
bajtów. Na przykład: -falign-functions=32
wyrównuje funkcje do następnej granicy 32-bajtowej, ale -falign-functions=24
zostanie wyrównane do następnej granicy 32-bajtowej tylko , jeśli można to zrobić, pomijając 23 bajty lub mniej.
-fno-align-functions
i -falign-functions=1
są równoważne i oznaczają, że funkcje nie będą wyrównane.
Niektóre asemblery obsługują tę flagę, gdy n jest potęgą dwóch; w tym przypadku jest on zaokrąglany w górę.
Jeśli n nie jest określone lub wynosi zero, użyj domyślnego ustawienia zależnego od urządzenia.
Włączone na poziomach -O2, -O3.
Nie może być wiele powodów ku temu, ale głównym z nich na x86 jest prawdopodobnie to:
Większość procesorów pobrać instrukcje w wyrównanych 16-bajtowych lub 32-bajtowych bloków. Może to być korzystne dla wyrównania krytycznych pozycji pętli i wpisów podprogramów przez 16, aby zminimalizować liczbę 16-bajtowych granic w kodzie. Alternatywnie, upewnij się, że nie ma granicy 16 bajtów w pierwszych kilku instrukcjach po wejściu krytycznej pętli lub wpisie podprogramu.
(Cytat z "Optymalizacja podprogramów w montażu języka" przez Agner Fog).
edit: Oto przykład, który pokazuje padding:
// align.c
int f(void) { return 0; }
int g(void) { return 0; }
Kiedy skompilowany przy użyciu gcc 4.4.5 z ustawieniami domyślnymi otrzymuję:
align.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <f>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: b8 00 00 00 00 mov $0x0,%eax
9: c9 leaveq
a: c3 retq
000000000000000b <g>:
b: 55 push %rbp
c: 48 89 e5 mov %rsp,%rbp
f: b8 00 00 00 00 mov $0x0,%eax
14: c9 leaveq
15: c3 retq
Podanie -falign-functions
podaje:
align.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <f>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: b8 00 00 00 00 mov $0x0,%eax
9: c9 leaveq
a: c3 retq
b: eb 03 jmp 10 <g>
d: 90 nop
e: 90 nop
f: 90 nop
0000000000000010 <g>:
10: 55 push %rbp
11: 48 89 e5 mov %rsp,%rbp
14: b8 00 00 00 00 mov $0x0,%eax
19: c9 leaveq
1a: c3 retq
Czy te NOPy nadal działają? Jeśli zatrzymają się na '80483af', to może to dopełnienie do wyrównania następnej funkcji do 8 lub 16 bajtów. – Mysticial
no po 4 węzłach idzie cieśnina do funkcji: __libc_csu_fini – olly
Jeśli NOPs zostały wstawione przez gcc wtedy nie sądzę, że będzie używał tylko 0x90, ponieważ istnieje wiele NOPów o zmiennej wielkości od [1-9 bajtów] (http://software.intel.com/en-us/forums/topic/307174) (10 jeśli używam [składnia gazu] (http://stackoverflow.com/a/12564044/995714)) –