A.D.Danilecki, Poznan, Polska
Politechnika Poznanska, Wydzial Informatyki i Zarzadzania
W tej chwili adanilecki _malpa_ cs.put.poznan.pl
Z wykorzystaniem wielu listow z uwagami od wielu autorow
Krótki wstęp do programowania z wykorzystaniem inline assemblera x86



spis treści dodatku

Ten dokument zawiera przetłumaczony i w swobodny sposób pozmieniany tekst standardu ELF. Dokument ten pochodzi z strony Briana Raitera , i został przetłumaczony i użyty za jego zgodą. Tłumaczenie A.D.Danilecki adanilecki _malpa_ cs.put.poznan.pl. Wszelkie błedy są efektem mojej kiepskiej znajomości angielskiego i nie powinny obciążać oryginalnych autorów. Proszę także o uwagi na temat jakości tłumaczenia i propozycje lepszych tłumaczeń kierować na adres adanilecki _malpa_ cs.put.poznan.pl .

lepsze kulawe tłumaczenie niż żadne? Czy też lepsze żadne tłumaczenie niż kiepskie? Jeśli znasz dobrze angielski nie zawracaj sobie głowy lekturą tego dokumentu i znajdź jego angielski oryginał.
W tej chwili dokument posaida wiele niespójności, błędów, tylko częściowo przeniesiony jest na.php i większość linków nie działa. Tłumacz (czyli ja :) ) będzie poprawiał dokument w wolnym czasie, jednakże nie będzie uprzedzał o zamieszczaniu poprawek. Czekaj na wersję 0.7 lub co jakiś czas (co dwa tygodnie co najmniej) sprawdzaj moją stronę www.


 
EXECUTABLE AND LINKABLE FORMAT (ELF)
Format pliku wykonywalnego i możliwego do połączenia.
 
Specyfikacja przenośnego formatu
 
Tool Interface Standards (TIS)
Standardy Interfejsu Narzędzia
 

    Spis treści

  1. Wstęp
  2. Pliki obiektowe
     
    Wprowadzenie
    Nagłówek ELF
    Sekcje
    Tablica łańcuchów
    Tablica Symboli
    Relokacja
  3. Ładowanie programu i dynamiczne łączenie
     
    Wprowadzenie
    Nagłówek programu
    Ładowanie programu
    Dynamiczne łączenie
  4. Biblioteka C
     
    Biblioteka C

Wstęp


ELF: Executable and Linking Format

Format pliku wykonywalnego i łączonego (Executable and Linking Format) pierwotnie został wymyślony i opublikowany przez UNIX System Laboratories (USL) jako część interfejsu binarnego aplikacji (Application Binary Interface) czyli tzw. ABI. Komitet standardów interfejsów narzędzi (Tool Interface Standards committee, TIS) wybrał ewoluujący standard ELF jako format przenośnego pliku .o dla najprzeróżniejszych systemów operacyjnych.

Intencją standardu ELF jest zunifikowanie rozwoju oprogramowania poprzez dostarczenie programistom zbioru binarnych interfejsów które będą dostępne dla wielu środowisk programistycznych i wielu systemów operacyjnych. Powinno to zredukować liczbę różnych implementacji interfejsu, w ten sposób zmniejszając potrzebę przekodowywania i rekompilacji kodu.

o tym dokumencie

Ten dokument jest przeznaczony dla programistów którzy tworzą pliki wykonywalne lub obiektowe dla różnych 32bitowych środowisk systemów operacyjnych.

Podzielony jest na trzy części:
Część 1 , ,,Pliki obiektowe'' opisuje obiektowe pliki ELF dla trzech głównych typów takich plików.
Część 2, ,,Ładowanie i dynamiczne łączenie Programu'' opisuje informacje zawarte w plikach obiektowych i akcje systemu tworzące działający program.
Część 3 , ,,Biblioteka C'' wymienia symbole zawarte w bibliotece systemowej libsys, standardowe procedury ANSI C i libc, oraz globalne symbole które są wymagane przez procedury libc.

Zauważ: Wszystkie odniesienia do architektury x86 zostały zmienione na odniesienia do architekury Intela.


1. Pliki obiektowe


Wprowadzenie

do spisu treści tej specyfikacji

Część 1 opisuje intelowski ABI dla plików obiektowych, nazywany ELF (Executable and Linking Format). Istnieją trzy główne typy takich plików:

Stworzone przez asembler i edytor łączenia( ang. link editor), pliki obiektowe są binarną reprezentacją programu przeznaczonymi do wykonywania bezpośrednio na procesorze. Programy które wymagają abstrakcyjnych warstw takie jak skrypty shella, są wyłączone z tych definicji.

Po materiale wprowadzającym, część pierwsza skupia się na formacie pliku i sposobie odniesienia go do budowy programów. Część druga opisuje również pliki obiektowe, koncentrując się na informacjach niezbędnych do uruchomienia programu.

Format Pliku

do spisu treści tej specyfikacji

Pliki obiektowe biorą udział w łączeniu (linkowaniu) programu (budowaniu programu) oraz wykonywaniu programu. Dla wygody i efektywności, format pliku obiektowego zapewnia równoległe widoki zawartości pliku, odwzierciedlające różne potrzeby tych działań. Rysunek 1-1 pokazuje organizację pliku obiektowego.

+ Rysunek 1-1: Format pliku obiektowego.
Widok ze strony linkera Widok od strony wykonywania


Nagłówek ELF Nagłówek ELF
Tablica nagłowka programu (opcja) Tablica nagłówka programu
Sekcja 1 Segment 1
... Segment 2
Sekcja n ...
Tablica nagłówków sekcji Tablica nagłówków sekcji (opcja)

Nagłówek ELF znajduje się na początku i zawiera ,,mapę drogową'' opisującą sposób organizacji pliku. Sekcje zawierają większą część informacji pliku obiektowego dla widoku dla linkera: instrukcje, dane, tablice symboli, informacje o przemieszczeniach (relokacji, ang. relocations), itd. Opis sekcji specjalnych pojawi się później w części pierwszej. Część druga omawia segmenty i widok pliku od strony wykonywania programu.

Tablica nagłówku programu , jeśli obecna, mówi systemowi w jaki sposób stworzyć obraz procesu. Pliku używane do budowy obrazu procesu (wykonania programu) muszą mieć tablicę nagłowka programu; pliki relokacyjne nie. Tablica nagłówków sekcji zawiera informacje opisujące sekcje pliku. Każda sekcja posiada wpis w tablicy; każdy taki wpis podaje informacje takie jak nazwa sekcji, rozmiar itd. Pliki używane podczas łączenia muszą mieć tablicę nagłówków sekcji, inne pliki obiektowe mogą lecz nie muszą jej zawierać.

ZAUWAŻ: Chociaż rysunek pokazuje tablicę nagłówka programu natychmiast po nagłówku ELF, a tablicę nagłówków sekcji dopiero po wszystkich sekcjach, właściwa struktura plików może się różnić od podanej. Co więcej, sekcje i segmenty nie posiadają żadnego ściśle określonego porządku. Tylko nagłówek ELF posiada określoną pozycję w pliku.

Reprezentacja danych

do spisu treści tej specyfikacji

Tak jak to tutaj opisujemy, format pliku obiektowego wspiera rozmaite procesory o 8-bitowej i 32-bitowej architekturze. Jednakże jego intencją jest rozszerzalność również na inne więcej- lub mniej- bitowe architektury. Plik obiektowy reprezentuje więc pewne dane kontrolne z formatem niezależnym od sprzętu, czyniąc możliwym zidentyfikowanie plików obiektowych i interpretację ich zawartości w prosty sposób. Pozostała część danych zawiera rozkazy dla procesora docelowego, niezależnie od tego na jakim sprzęcie plik został utworzony.

+ Rysunek 1-2: 32-Bitowe typy danych
Nazwa Rozmiar Wyrównywanie Cel




Elf32_Addr 4 4 Adresy w programie bez znaku
Elf32_Half 2 2 Liczby całkowite średnie bez znaku
Elf32_Off 4 4 Offset w pliku bez znaku
Elf32_Sword 4 4 Wielkie liczby całkowite ze znakiem
Elf32_Word 4 4 Wielkie liczby całkowite bez znaku
unsigned char 1 1 Małe liczby całkowite bez znaku

Wszystkie struktury danych które definicuje format pliku podążają za ,,naturalnymi'' wskazówkami co do rozmiaru i wyrównywania odpowiednich klas. Jeśli jest to potrzebne, struktury danych zawierają z góry określone wypełnianie (ang. padding) dla zapewnienia odpowiedniego wyrównania (ang. alignment) dla 4-bajtowych obiektów, tak aby zapewniać wielkość struktur będącą wielokrotnościami czwórki, itd. Dane posiadają również odpowiednie wyrównanie od początku pliku, to znaczy że członek typu Elf32_Addr zostanie wyrównany w 4-bajtowych granicach wewnątrz pliku.

Dla zapewnienia przenośności, ELF nie używa pól bitowych.


Nagłówek ELF


do spisu treści tej specyfikacji

Niektóre struktury kontrolne w plikach obiektowych mogą rosnąć, ponieważ nagłówek ELF zawiera ich właściwe rozmiary. Jeżeli format pliku obiektowego się zmienia, program może odkryć że struktury kontrolne są mniejsze lub większe niż tego oczekiwał. Program może więc ignorować dodatkową informację. Traktowanie brakującej informacji zależy od kontekstu i zostanie wyspecyfikowane gdy/jeśli zostaną zdefiniowane dodatkowe rozszerzenia.

+ Rysunek 1-3: Nagłówek ELF
#define EI_NIDENT 16
typedef struct {
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx
} Elf32_Ehdr;

			  Identyfikacja ELF

Jak już wspomniano wyżej, ELF zapewnia plikowi obiektowemu ramę do 
współpracy z wieloma procesorami, wieloma sposobami kodowania danych, i
wieloma klasami architektur. Aby wpierać te rodziny plików obiektowych,
początkowe bajty pliku mówią jak interpretować plik, niezależnie
od procesora na którym się o to dowiadujemy i niezależnie od pozostałej
zawartości pliku.

Początkowe bajty nagłówka ELF (i pliku obiektowego) odpowiadają polu
e_ident.

+ Rysunek 1-4: e_ident[] indeksy identyfikacji 

  Nazwa          Wartość Przeznaczenie
  ====           =====  =======
  EI_MAG0	     0  Identifikacja pliku
  EI_MAG1	     1  Identifikacja pliku
  EI_MAG2	     2  Identifikacja pliku
  EI_MAG3	     3  Identifikacja pliku
  EI_CLASS	     4  Klasa pliku
  EI_DATA	     5  Kodowanie danych
  EI_VERSION	     6  Wersja pliku
  EI_PAD	     7  Początek dopełniających bajtów 
  EI_NIDENT	    16  rozmiar e_ident[]

Te indekst dotyczą bajtów które przechowują następujące wartości.

* od EI_MAG0 do EI_MAG3

  Pierwsze 4 bajty pliku przechowują ,,magic number'' (liczbę magiczną :) ,
która identyfikuje plik obiektowy ELF.

                  Nazwa      Wartość Pozycja
                  ====       =====  ========
		  ELFMAG0    0x7f   e_ident[EI_MAG0]
                  ELFMAG1    'E'    e_ident[EI_MAG1]
                  ELFMAG2    'L'    e_ident[EI_MAG2]
                  ELFMAG3    'F'    e_ident[EI_MAG3]

* EI_CLASS

Kolejny bajt, e_ident[EI_CLASS], identyfikuje klasę pliku.

                 Nazwa          Wartość Znaczenie
                 ====           =====  =======
                 ELFCLASSNONE       0  Błędna klasa
                 ELFCLASS32         1  obiekty 32-bit 
		 ELFCLASS64         2  obiekty 64-bit

Format pliku jest przeznaczony by być przenośnym pomiędzy architekturami
o różnych rozmiarach (np 32-bitowe, 64-bitowe), bez wyznaczania 
sprzętu o rozmiarze najmniejszym lub największym. Klasa ELFCLASS32 wspiera
architekturę o plikach i rozmiarze pamięci wirtualnej do 4Gb; używa
podstawowych typów zdefiniowanych wyżej.

  Klasa ELFCLASS64 jest zarezerwowana dla architektur 64-bitowych. Jej 
pojawienie się tutaj pokazuja jak plik obiektowy może się zmienić, ale w 
innym przypadku format 64bitowy jest niewyspecyfikowany. Inne klasy będą
definiowane w miarę potrzeby, z różnymi typami prostymi i rozmiarami dla
danych plików obiektowych.

* EI_DATA
  
  Bajt e_ident[EI_DATA] definiuje sposób kodowania danych specyficznych dla
procesora w pliku obiektowym. Następujące kodowania są zdefiniowane w tej chwili

             Nazwa          Wartość Znaczenie
             ====           =====  =======
	     ELFDATANONE        0  Błędny sposób kodowania
             ELFDATA2LSB        1  Patrz niżej
             ELFDATA2MSB        2  Patrz niżej

  Więcej sposobów na temat kodowania pojawia się poniżej. Inne wartości
są zarezerwowane i będą przydzielane nowy sposobom kodowanie jeśli
okaże się to potrzebne.

* EI_VERSION

  Bajt e_ident[EI_VERSION] definiuje numer wersji nagłówka ELF.
Obecnie ta wartość musi sie równać EV_CURRENT, tak jak to objaśniono
wyżej dla e_version.

* EI_PAD

  Ta wartość oznacza początek nieużywanych bajtów w e_ident. Te bajty są 
zarezerwowane i ustawione na zero; programy czytające pliki obiektowe
powinny je ignorować. Wartość EI_PAD zmieni się w przyszłości gdy obecnie
nieużywane bajty otrzymają jakieś znaczenie.

 Kodowanie danych pliku specyfikuje jak interpretować proste obiekty w
pliku. Jak opisano wyżej, klasa ELFCLASS32 używa obiektów które 
zajmują 1, 2, i 4 bajty. Pod zdefiniowanym kodowaniem, obiekty są 
reprezentowane jak pokazano niżej. Numery bajtów występują w górnych lewych
rogach.

Kodowanie ELFDATA2LSB definiuje 2-komplementarne(dopełniane do 2) wartości,
 z najmniej znaczącym bajtem zajmującym najniższy adres .

+ Rysunek 1-5: Kodowanie danych ELFDATA2LSB

               0------+
      0x0102   |  01  |
               +------+
               0------1------+
    0x010204   |  02  |  01  |
               +------+------+
               0------1------2------3------+
  0x01020304   |  04  |  03  |  02  |  01  |
               +------+------+------+------+

ELFDATA2MSB definiuje 2-komplementarne wartości, z najbardziej znaczącym bajtem
zajmującym najniższy adres.

+ Rysunek 1-6: Kodowanie danych ELFDATA2MSB

               0------+
      0x0102   |  01  |
               +------+
               0------1------+
    0x010204   |  01  |  02  |
               +------+------+
               0------1------2------3------+
  0x01020304   |  01  |  02  |  03  |  04  |
               +------+------+------+------+


			 Informacje o architekturze

Dla identyfikacji pliku w e_ident, 32-bitowa architektura Intela
wymaga następujących wartości.

+ Rysunek 1-7: 32-bitowa identyfikacja dla architektury Intela, e_ident 

  Pozycja            Wartość
  ========           =====
  e_ident[EI_CLASS]  ELFCLASS32
  e_ident[EI_DATA]   ELFDATA2LSB

Identyfikacja procesora pozostaje w polu e_machine nagłówka ELF i musi
posiadać wartość EM_386

Pole e_flags nagłówka ELF przechowuje flagi bitowe związane z plikiem.
32-bitowa architektura Intela nie definiuje zadnych flag, tak więc
to pole zawiera zero.


   =========================== Sekcje ===========================


Tablica nagłówków sekcji pliku obiektowego pozwala zlokalizować wszystkie sekcje
pliku.  Tablica nagłówków sekcji jest tablicą struktur Elf32_Shdr opisanych 
niżej. Indeks tablicy nagłówków sekcji jest wskaźnikiem do tej tablicy.
Pole e_shoff nagłówka ELF podaje offset w bajtach od początku pliku do 
tablicy nagłówków sekcji; e_shnum mówi ile pozycji zawiera tablica; e_shentsize
podaje rozmiar w bajtach każdej pozycji.

Niektóre indeksy tablicy nagłówków sekcji są zarezerwowane; plik obiektowy
nie może posiadać sekcji dla tych specjalnych indeksów.

+ Rysunek 1-8 : Specjalne wartości indeksów sekcji 

  Nazwa           Wartość
  ====             =====
  SHN_UNDEF            0
  SHN_LORESERVE   0xff00
  SHN_LOPROC      0xff00
  SHN_HIPROC      0xff1f
  SHN_ABS         0xfff1
  SHN_COMMON      0xfff2
  SHN_HIRESERVE   0xffff

* SHN_UNDEF

  Ta wartość znaczy niezdefiniowane, brakujące lub w inny sposób pozbawione
znaczenie odwołanie do sekcji. Na przykład symbol ,,defined'' w odniesieniu
do sekcji numer SHN_UNDEF jest symbolem niezdefiniowanym.

ZAUWAŻ: Chociaż indeks 0 jest zarezerwowany jako wartość niezdefiniowana, 
tablica nagłówków sekcji zawiera pozycję dla indeksu 0. To znaczy, jeśli
pole nagłówka ELF e_shnum wynosi 6, czyli że plik ma 6 pozycji w tablicy
nagłówków sekcji, to posiadają one numery od 0 do 5. Zawartość początkowej
pozycji jest zdefiniowana później w tej sekcji.

* SHN_LORESERVE

  Ta wartość definiuje dolną granicę zbioru zarezerwowanych indeksów.

* od SHN_LOPROC do SHN_HIPROC

  Wartości w tym zbiorze są zarezerwowane dla semantyki specyficznej dla
procesora.

* SHN_ABS

  Ta wartość definiuje bezwzlędną wartość dla odpowiadającego odwołania.
Na przykład symbole zdefiniowane jako względne dla sekcji numer SHN_ABS 
posiadają bezwzględne, absolutne wartości i nie dotyczy ich relokacja
(ang. relocation). 

* SHN_COMMON

  Symbole zdefiniowane w tej sekcji są symbolami wspólnymi (common symbols),
tak jak FORTRAN COMMON albo niezalokowane zewnętrzne zmienne C.

* SHN_HIRESERVE

  Ta wartość definiuje górną granicę zbioru zarezerwowanych indeksów. 
System rezerwuje indeksy pomiędzy SHN_LORESERVE i SHN_HIRESERVE włącznie;
wartości te nie odnoszą się do tablicy nagłówków sekcji, to jest tablica
nagłówków sekcji nie zawiera pozycji dla zarezerwowanych indeksów.

Sekcje zawierają wszystkie informacje w pliku obiektowym, poza nagłówkiem
ELF, tablicą nagłówka programu i tablicą nagłówków sekcji. Co więcej, sekcje
pliku obiektowego spełniają kilka warunków.

* Każda sekcja w pliku obiektowym posiada dokładnie jeden nagłówek sekcji który
  ją opisuje. Mogą istnieć nagłówki sekcji nie posiadające sekcji.

* Każda sekcja zajmuje jedną ciągłą (możliwe że pustą) sekwencję bajtów
 w pliku.

* Sekcje w pliku nie mogą się nakładać. Żaden bajt nie może być w więcej niż
jednej sekcji.

* Plik obiektowy może posiadać przestrzeń nieaktywną. Różne nagłówki i sekcje
mogą nie pokrywać każdego bajtu w pliku obiektowym. Zawartość takich danych 
nieaktywnych jest niezdefiniowana.

Nagłówek sekcji posiada następującą strukturę.

+ Rysunek 1-9: Nagłówek sekcji

  typedef struct {
      Elf32_Word	sh_name;
      Elf32_Word	sh_type;
      Elf32_Word	sh_flags;
      Elf32_Addr	sh_addr;
      Elf32_Off		sh_offset;
      Elf32_Word	sh_size;
      Elf32_Word	sh_link;
      Elf32_Word	sh_info;
      Elf32_Word	sh_addralign;
      Elf32_Word	sh_entsize;
  } Elf32_Shdr;

* sh_name

  To pole specyfikuje nazwę sekcji. Jego wartością jest wskaźnik do 
tablicy nazw nagłówków sekcji [zobacz ,,Tablica nazw'' poniżej], podając
lokalizację łańcucha zakończonego znakiem pustym.

* sh_type

  To pole szufladkuje zawartość i semantykę sekcji. Typy sekcji są opisane
niżej.

* sh_flags

  Sekcje wspierają jednobitowe flagi opisujące różne atrybuty . Definicje
flag pojawiają się niżej.

* sh_addr

  Jeśli sekcja pojawia się w obrazie pamięci procesu, to pole podaje 
pole w którym pierwszy bajt sekcji się pojawia. Wpw, to pole zawiera zero.

* sh_offset

  Wartość tego pola podaje offset w bajtach od początku pliku do 
pierwszego bajtu sekcji. jeden typ sekcji, SHT_NOBITS opisany niżej, nie 
zajmuje miejsca w pliku, i jego sh_offset zajmuje koncepcyjne (ang conceptual??)
umieszczenie w pliku.

* sh_size

  To pole podaje rozmiar sekcji w bajtach. Jeżeli typ sekcji nie jest
 SHT_NOBITS, sekcja zajmuje sh_size bajtów w pliku. Sekcja typu 
SHT_NOBITS może posiadać rozmair niezerowy, ale i tak nie zajmuje miejsca
w pliku.

* sh_link

  To pole zawiera łącze do wskaźnika na tablicę nagłówków sekcji
(ang.section header table index link), którego  interpretacja zależy od typu
sekcji. Tablica poniżej opisuje wartości.  

* sh_info

 To pole zawiera dodatkową informację, której interpretacja zależy od typu
sekcji. Tablica poniżej opisuje wartości jakie może przybierać.

* sh_addralign
  
  Niektóre sekcje posiadają ograniczenie na wyrównywanie (alignment)
adresów. na przykład, jeśli sekcja zawiera podwójne słowo, system musi
zapewnić wyrównanie do podwójnego słowa dla całej sekcji. Oznacza to że
wartość pola sh_addr modulo wartość sh_addralign musi wynosić zero
(ang.  That is, the value of sh_addr must be congruent to 0, modulo the value of sh_addralign.) Obecnie tylko zero i dodatnie całkowite potęgi dwójki są 
dozwolone. Wartość 0 i 1 oznacza że sekcja nie posiada ograniczeń na 
wyrównywanie.


* sh_entsize

  Niektóre sekcje przechowują tablice o stałych rozmiarach pozycji, takie
jak tablice symboli. Dla takich sekcji to pole podaje rozmiar w bajtach
każdej pozycji. Pole to zawiera zero jeśli sekcja nie posiada tablicy
o stałych rozmiarach pozycji.
 

Pole sh_type nagłówka sekcji podaje sematykę sekcji.

+ Rysunek 1-10: Typy sekcji, sh_type

  Name               Value
  ====               =====
  SHT_NULL               0
  SHT_PROGBITS           1
  SHT_SYMTAB             2
  SHT_STRTAB	         3
  SHT_RELA	         4
  SHT_HASH	         5
  SHT_DYNAMIC            6
  SHT_NOTE	         7
  SHT_NOBITS	         8
  SHT_REL	         9
  SHT_SHLIB             10
  SHT_DYNSYM            11
  SHT_LOPROC    0x70000000
  SHT_HIPROC    0x7fffffff
  SHT_LOUSER    0x80000000
  SHT_HIUSER    0xffffffff

* SHT_NULL

  Ta wartość oznacza że nagłowek sekcji jest nieaktywny i nie odnosi się
do żadnej istniejącej sekcji. Inne pola nagłówka sekcji posiadają 
niezdefiniowane, dowolne wartości.

* SHT_PROGBITS

  Ta sekcja zawiera informacje zdefiniowane przez program, których
format i znaczenie jest całkowicie zależne od programu.

* SHT_SYMTAB and SHT_DYNSYM

  Ta sekcja zawiera tablicę symboli. Obecnie plik obiektowy może posiadać tylko
jedną sekcję każdego typu, lecz to ograniczenie może zostać złagodzone w 
przyszłości. Zazwyczaj SHT_SYMTAB zapewnia symbole do edytowania łączy/linków
(ang. link editing), chociaż może również zostać użyte do dynamicznego
łączenia (ang. dynamic linking). Plik obiektowy może również posiadać sekcję
SHT_DYNSYM, która zawiera minimalny zbiór symboli potrzebnych przy 
dynamicznym łączeniu. Zobacz ,,Tablice symboli'' by dowiedzieć się szczegółów.

* SHT_STRTAB

  Ta sekcja zawiera tablicę nazw (ang. string table). Plik obiektowy może 
posiadać wiele sekcji tego typu. Po więcej szczegółów udaj się do rozdziału 
,,Tablica Nazw''.

* SHT_RELA

  (?) Sekcja zawiera pozycje relokacji z góry nadanymi dodatkami, takimi jak
typ Elf32_Rela dla 32-bitowej klasy plików obiektowych. (???? ang. 
The section holds relocation entries with explicit addends, such as
type Elf32_Rela for the 32-bit class of object files). Plik obiektowy
może posiadać wiele relokacyjnych sekcji. Zobacz ,,Relokacja'' poniżej 
po więcej szczegółów.

* SHT_HASH

  Sekcja zawiera haszową (mieszającą) tablicę symboli. Wszystkie obiekty
biorące udział w dynamicznym łączeniu muszą zawierać taką tablicę. Obecnie
plik obiektowy może posiadać tylko jedną haszową tablicę, ale to ograniczenie
może zostać złagodzone w przyszłości. Zobacz ,,Tablica Haszowa'' w części
drugiej po więcej szczegółów.

* SHT_DYNAMIC

  Sekcja zawiera informacje dla dynamicznego łączenia. Obecnie plik obiektowy
może posiadać tylko jedną dynamiczną sekcję, ale to ograniczenie może ulec
złagodzeniu w przyszłości. Zobacz ,,Sekcja dynamiczna'' w części drugiej
po więcej szczegółów.

* SHT_NOTE

  Sekcja zawiera informacje które znaczą w pewien sposób plik. Zobacz ,,Sekcje
z uwagami'' w części drugiej po więcej szczegółów.

* SHT_NOBITS

  Sekcja tego typu nie zajmuje przestrzenie w pliku ale poza tym przypomina
sekcję SHT_PROGBITS. Chociaż ta sekcja nie zawiera bajtów, pole sh_offset
zawiera koncepcyjny (ang. conceptual) ofset pliku.

* SHT_REL

  Sekcja zawiera pozycje relokacji bez z góry nadanych dodatków takich jak
typ Elf32_Rel dla 32bitowych klas plików obiektowych (?). Plik obiektowy może
posiadać wiele sekcji relokacyjnych. Zobacz ,,Relokacja'' poniżej po więcej
szczegółów.

* SHT_SHLIB

  Ta sekcja jest zarezerwowana ale nie posiada wyspecyfikowanej semantylo.
Programy zawierające tą sekcję nie są zgodne z ABI (aplication binary
interface).

* od SHT_LOPROC do SHT_HIPROC

  Wartości w tym zbiorze są zarezerwowane dla semantyki zależnej od procesora.

* SHT_LOUSER

  Ta wartość podaje dolne ograniczenie zbioru indeksów zarezerwowanych dla
programów użytkowych.

* SHT_HIUSER
  
  Ta wartość podaje górną granicę indeksów zarezerwowanych dla programów
użytkowych. Typy sekcji pomiędzy SHT_LOUSER i SHT_HIUSER mogą być używane
przez aplikacje, bez wchodzenia w konflikt z bieżącymi lub zdefiniowanymi
w przyszłości systemowymi typami sekcji.

Inne wartości określające typy sekcji są zarezerwowane. Tak jak wspomniano
wcześniej, nagłówek sekcji dla indeksu 0 (SHN_UNDEF) istnieje, nawet pomimo
tego że indeks ten znaczy niezdefiniowane odnośniki do sekcji. Ta pozycja
zawiera :

+ Rysunek 1-11: Pozycja w tablicy nagłówków sekcji: Indeks 0

  Nazwa           Wartość  Uwagi
  ====            =====    ====
  sh_name           0      brak nazwy 
  sh_type        SHT_NULL  Nieaktywna 
  sh_flags          0      Brak flag 
  sh_addr           0      Brak adresu
  sh_offset         0      Brak ofestu pliku
  sh_size           0      Brak rozmiaru
  sh_link	SHN_UNDEF  Brak informacji o łączeniu
  sh_info	    0      Brak informacji pomocniczych
  sh_addralign	    0      Brak dopełniania (alignment)
  sh_entsize        0      Brak pozycji

Pole sh_flags nagłówka sekcji zawiera bitową flagę która opisuje atrybuty
sekcji. Zdefiniowane wartości pojawiają się w tablicy niżej, inne wartości
są zarezerwowane.

+ Rysunek 1-12: Flagi atrybutów sekcji, sh_flags

  Nazwa               Wartość
  ====                =====
  SHF_WRITE             0x1
  SHF_ALLOC             0x2
  SHF_EXECINSTR         0x4
  SHF_MASKPROC   0xf0000000

Jeśli bit flagi jest ustawiony w sh_flagsm atrybut jest ,,włączony'' dla
tej sekcji. W przeciwnym razie atrybut jest ,,wyłączony'' lub nie posiada
zastosowania. Atrybuty niezdefiniowane są ustawione na zero.

* SHF_WRITE
  
  Sekcja zawiera dane które powinny byc zapisywalne podczas wykonywania procesu.

* SHF_ALLOC

  Sekcja zajmuje pamięć podczas wykonywania procesu. Pewne sekcje kontrolne
nie znajdują się w obrazie pamięci pliku obiektowego; ten atrybut jest wyłączony
dla tych sekcji.

* SHF_EXECINSTR

  Sekcja zawiera wykonywalne kody instrukcji maszynowych.

* SHF_MASKPROC

  Wszystkie bity włączone w tą masję są zarezerwowane dla semantyki specyficznej
dla procesora.

Dwa pola w nagłówku sekcji, sh_link i sh_info, zawierają specjalne informacje, 
zależące od typu sekcji.

+ Rysunek 1-13: Interpretacja sh_link i sh_info  

  sh_type      sh_link                        sh_info
  =======      =======                        =======
  SHT_DYNAMIC  Indeks nagłówka sekcji w tablicy 0
               nazw używanej przez pozycje 
               w tej sekcji           
  SHT_HASH     Indeks nagłówka sekcji w tablicy 0
               symboli do której odnosi się 
               tablica haszowa.   
  SHT_REL,     Indeks nagłówka sekcji w       Indeks nagłówka sekcji dla sekcji
  SHT_RELA     związanej tablicy symboli.     do której odnosi się relokacja
  SHT_SYMTAB,  Indeks nagłówka sekcji w       O jeden większe niż indeks tablicy
  SHT_DYNSYM   związanej tablicy nazw.        symboli dla ostatniego lokalnego
                                              symbolu (wiążącego STB_LOCAL).
  inne         SHN_UNDEF                      0


			   Sekcje specjalne

Różne sekcje przechpwują program i informacje kontrolne. Sekcje wyszczególnione
w liście poniżej są używane przez system i posiadają określone typy i atrybuty.

+ Rysunek 1-14: Sekcje specjalne

  Nazwa        Typ            Atrybuty  
  ====         ====           ==========
  .bss         SHT_NOBITS     SHF_ALLOC+SHF_WRITE
  .comment     SHT_PROGBITS   brak
  .data        SHT_PROGBITS   SHF_ALLOC+SHF_WRITE
  .data1       SHT_PROGBITS   SHF_ALLOC+SHF_WRITE
  .debug       SHT_PROGBITS   brak
  .dynamic     SHT_DYNAMIC    zobacz niżej
  .dynstr      SHT_STRTAB     SHF_ALLOC
  .dynsym      SHT_DYNSYM     SHF_ALLOC
  .fini        SHT_PROGBITS   SHF_ALLOC+SHF_EXECINSTR
  .got         SHT_PROGBITS   zobacz niżej
  .hash        SHT_HASH       SHF_ALLOC
  .init        SHT_PROGBITS   SHF_ALLOC+SHF_EXECINSTR
  .interp      SHT_PROGBITS   zobacz niżej
  .line        SHT_PROGBITS   brak
  .note        SHT_NOTE       brak 
  .plt         SHT_PROGBITS   zobacz niżej
  .rel   SHT_REL        zobacz niżej
  .rela  SHT_RELA       zobacz niżej
  .rodata      SHT_PROGBITS   SHF_ALLOC
  .rodata1     SHT_PROGBITS   SHF_ALLOC
  .shstrtab    SHT_STRTAB     brak
  .strtab      SHT_STRTAB     zobacz niżej
  .symtab      SHT_SYMTAB     zobacz niżej
  .text        SHT_PROGBITS   SHF_ALLOC+SHF_EXECINSTR

* .bss

  Ta sekcja zawiera niezainicjowane dane które odnoszą się do obrazu
pamięci programu. Z definicji system inicjalizuje te dane zerami gdy program
rozpoczyna działanie. Sekcja ta nie zajmuje przestrzeni w pliku, tak jak
to wynika z typu sekcji, SHT_NOBITS

* .comment

  Ta sekcja zawiera informacje kontrolne dotyczące wersji.

* .data and .data1

  Te sekcje zawierają zainicjalizowane dane które odnoszą się do obrazu pamięci
  programu.               

* .debug

  Ta sekcja zawiera informację dla debuggingu. Zawartość jest niezdefiniowana.

* .dynamic

  Ta sekcja zawiera informacje dotyczące dynamicznego łączenia. Atrybuty sekcji
  zawierają SHF_ALLOC. To czy bit SHF_WRITE jest ustawiony zależy od procesora.
  Patrz część druga po więcej informacji.

* .dynstr

  Ta sekcja zawiera łańcuchy potrzebne podczas dynamicznego łączenia, zazwyczaj
  łańcuchy reprezentujące nazwy związane z pozycjami tablicy symboli. Patrz
  część druga po więcej informacji.        

* .dynsym

  Ta sekcja zaiwera tablicę symboli dla dynamicznego łączenia, tak jak opisuje
  to ,,tablica symboli''. Patrz część druga po więcej informacji.

* .fini

  Ta sekcja zawiera wykonywalne instrukcje które odnoszą się do kodu kończącego
  proces. To znaczy, gdy program kończy się normalnie, system zapewnia wykonanie
 kodu tej sekcji.

* .got

  Ta sekcja zawiera tablicę globalnych ofsetów. Zobacz ,,Sekcje specjalne'' w
w części 1 i ,,Tablica globalnych ofsetów'' w części 2 po więcej informacji.

* .hash

  Ta tablica zawiera haszową tablicę symboli. Zobacz ,,Tablica Hashowa'' w 
części drugiej po więcej informacji.

* .init

  Ta sekcja zawiera instrukcje które należą do kodu inicjalizacyjnego procesu.
Oznacza to że kiedy proces startuje, system wykonuje kod w tej sekcji zanim
wywoła główny punkt ,,wejścia'' programu (ang. entry point) (dla programów
w C będzie to na przykład main).

* .interp

  Ta sekcja zawiera nazwę scieżki interpretera programu. Jeśli plik 
posiada ładowalny segment który zawiera tą sekcję, atrybuty sekcji będą
zawierać bit SHF_ALLOC. W przeciwnym wypadku ten bit będzie wyczyszczony.
Zajrzyj do części drugiej po więcej informacji.

* .line

  Ta sekcja zawiera informacje o numerach linii dla debuggingu, które 
opisują związek między liniami programu źródłowego i kodem maszynowym. Zawartość
jest niezdefiniowana.

* .note

  Ta sekcja zawiera informacje w formacie opisanym przez ,,Sekcje z uwagami''
w części drugiej.

* .plt

  Ta sekcja zawiera tablicę procedury łączenia. Zobacz ,,Sekcje specjalne''
w części pierwszej i ,,tablica procedury łączenia'' w części drugiej po
 więcej informacji. 

* .rel and .rela
  
  Te sekcje zawierają informacje relokacyjne, tak jak poniżej opisuje to
,,Relokacja''. Jeśli plik zawiera ładowalny segment zawierający relokację, 
atrybuty sekcji będą zawierać bit SHF_ALLOC, wpw ten bit będzie wyczyszczony.
 odnosi się do sekcji do której odnosi się relokacja. W ten sposób
sekcja relokacji dla .text normalnie będzie posiadać nazwę .rel.text lub
.rela.text. 

* .rodata and .rodata1

  Te sekcje zawierają dane tylko do odczytu które odnoszą się typowo 
do niezapisywalnego segmentu w obrazie procesu. Zobacz ,,Nagłówek programu''
w części drugiej po więcej szczegółów.

* .shstrtab

  Ta sekcja zawiera nazwy sekcji.

* .strtab

  Ta sekcja zawiera łańcuchy, zazwyczaj łańcuchy reprezentujące nazwy
związane z pozycjami tablicy symboli. Jeśli plik posiada ładowalny segment który
zawiera tablicę łańcuchów (nazw) symboli, atrybuty sekcji będą zawierać bit
SHF_ALLOC. W przeciwnym wypadku ten bit zostanie wyczyszczony.

* .symtab

  Ta skecja zawiera tablicę symboli tak jak to opisuje ,,Tablica symboli''.
Jeśli plik zawiera ładowalny segment który zawiera tablicę symboli, atrybuty
sekcji będą zawierać bit SHF_ALLOC. Wpw bit ten pozostanie wyczyszczony.

* .text

  Ta sekcja zawiera ,,tekst'', kod, wykonywalne instrukcje programu.

Nazwy sekcji zaczynające się od kropki są zarezerwowane dla systemu, 
aczkolwiek aplikacje mogą używać tych sekcji jeśli ich istniejące znaczenie
jest wystarczające. Aplikacje mogą używać nazw bez kropki by uniknąć 
konfliktów z sekcjami systemowymi. Format pliku obiektowego pozwala definiować
sekcje nie zawierające się w liście wyżej. Plik obiektowy może posiadać
więcej jak jedną sekcję z tą samą nazwą.

  Nazwy sekcji zarezerwowane dla architektury procesora są konstruowane
poprzez przyłączenia skrótu określającego architekturę z przodu nazwy sekcji.
Nazwa powinna być wzięta z nazwy architektur użytych dla e_machine. 
Na przykład .BLA.psect oznacza sekcję psect zdefiniowaną dla architektury
BLA. Istniejące rozszerzenia są nazywane ich historycznymi nazwami.


		         Istniejące rozszerzenia
		       ==========================
			 .sdata     .tdesc
			 .sbss      .lit4
			 .lit8      .reginfo
			 .gptab     .liblist
			 .conflict


   ========================= Tablica nazw =========================


Sekcje z tablicami nazw (łańcuchów) zawierają zakończone znakiem
pustym sekwencje znaków, powszechnie nazywane łańcuchami. Plik obiektowy
używa tych łańcuchów do reprezentowania symboli i nazw sekcji. Można
dostać się do łańcucha za pomocą indeksu w sekcji tablicy nazw. Pierwszy bajt,
o indeksie zero, musi z definicji zawierać znak pusty. Tak samo ostatni bajt
tablicy nazw również z definicji musi zawierać znak pusty, zapewniając że
na pewno wszystkie łańcuchy zakończą się znakiem pustym. Łańcuch którego indeks
wynosi zero nie definiuje żadnej nazwy lub inaczej mówiąc nazwę pustą, zależnie
od kontekstu. Dozwolona jest pusta sekcja tablicy nazw; pole sh_size 
nagłówka sekcji w takim przypadku zawiera zero. Niezerowe indeksy są 
nieprawidłowe dla tablicy pustego łańcucha.

Pole sh_name nagłówka sekcji zawiera indeks do nagłówka sekcji sekcji tablicy
nazw, tak ja to jest wyznaczone przez pole e_shstrndx nagłówka ELF. 
Następujące rysunki pokazują tablicę nazw z 25 bajtami i łańcuchami połączonymi
z różnymi indeksami.


       Indeks  +0   +1   +2   +3   +4   +5   +6   +7   +8   +9
       =====   ==   ==   ==   ==   ==   ==   ==   ==   ==   ==
          0    \0   n    a    m    e    .    \0   V    a    r     
         10    i    a    b    l    e    \0   a    b    l    e
         20    \0   \0   x    x    \0


+ Rysunek 1-15: Indeksy tablicy nazw 

  Indeks  Łańcuch
  =====   ======
      0   żaden 
      1   "name."
      7   "Variable"
     11   "able"
     16   "able"
     24   Łańcuch pusty 

Tak jak  pokazuje to przykład, indeks tablicy nazw może odnosić się do 
jakiegolwiek bajtu w sekcji. Łańcuch może pojawiać się więcej razy niż razl
mogą istnieć wskaźniki do podłańcuchów i może istnieć wiele wskaźników
do  pojedyńczego łańcucha. Dozwolone są również łańcuchy do których nie istnieje
żaden wskaźnik.

   ========================= Tablica Symboli =========================


Tablica symboli pliku obiektowego przechowuje informacje potrzebne
do zlokalizowania i relokacji symbolicznych definicji i referencji w
programie. Indeks tablicy symboli jest wskaźnikiem do tej tablicy. 
Indeks zerowy zarówno wskazuje początkową pozycję w tablicy jak i służy
za niezdefiniowany indeks symbolu. Zawartość początkowej pozycji są 
zdefiniowane później w tym punkcie.

                             Nazwa      Wartość
                             =====      =======
			     STN_UNDEF      0

Pozycja tablicy symboli posiada następujący format.

+ Rysunek 1-16: Pozycja tablicy symboli 

  typedef struct {
      Elf32_Word	st_name;
      Elf32_Addr	st_value;
      Elf32_Word	st_size;
      unsigned char	st_info;
      unsigned char	st_other;
      Elf32_Half	st_shndx;
  } Elf32_Sym;

* st_name

  To pole zawiera indeks do tablicy nazw symboli pliku obiektowego, która
zawiera znakową reprezentację nazw symboli. Jeśli wartość jest niezerowa, 
reprezentuje ono indeks tablicy nazw który podaje nazwę symbolu. Wpw pozycja
tablicy symboli nie posiada nazwy.

Zauważ: Zewnętrzne symbole C posiadają takie same nazwy w C i tablicach
symboli plików obiektowych.

* st_value

  To pole podaje wartość związanego symbolu. Zależnie od kontekstu może
to być wartość absolutna, adres itd. Szczegóły pojawiają się niżej.

* st_size

  Wiele symboli posiada rozmiary z nimi związane. Na przykład rozmiar
obiektu danych jest to numer bajtów zawartych w tym obiekcie. To pole
zawiera 0 jeśli symbol nie posiada rozmiaru lub jego rozmiar jest nieznany.

* st_info

  To pole definiuje typ symbolu  i związane z nim atrybuty. Lista wartości
i ich znaczeń pojawia się poniżej. Następujący kod pokazuje jak operować
tymi wartościami.

    #define ELF32_ST_BIND(i)	((i)>>4)
    #define ELF32_ST_TYPE(i)	((i)&0xf)
    #define ELF32_ST_INFO(b, t)	(((b)<<4)+((t)&0xf))

* st_other

  To pole obecnie zawiera 0 i nie posiada zdefiniowanego znaczenia.

* st_shndx

  Każda pozycja tablicy symboli jest ,,zdefiniowana'' w relacji do jakiejś
sekcji. To pole zawiera odpowiedni indeks do tablicy nagłówków sekcji. Jak
pokazuje to rysunek 1-8 {*} oraz opisuje związany tekst, niektóre indeksy
sekcji maja specjalne znaczenie.

Wiązanie symbolu determinuje jego widoczność i zachowanie podczas łączenia.

+ Rysunek 1-17: Wiązanie symbolu, ELF32_ST_BIND

  Nazwa       Wartość
  ====        =====
  STB_LOCAL       0
  STB_GLOBAL      1
  STB_WEAK        2
  STB_LOPROC     13
  STB_HIPROC     15

* STB_LOCAL

  Lokalne symbole nie są widoczne poza plikiem obiektowym zawierającym ich
definicję. Lokalne symbole o tej samej nazwie mogą istnieć w wielu plikach
współdziałając między sobą.

* STB_GLOBAL

  Symbole globalne są widoczne w wszystkich plikach obiektowych które są
łączone. Jedna definicja symbolu globalnego jest wystarczająca do referencji
do tego samego symbolu globalnego w innym pliku.

* STB_WEAK

  Słabe symbole przypominają symbole globalne, ale ich definicja posiada
słabszy priorytet.

* od STB_LOPROC do STB_HIPROC

  Wartości w tym domkniętym zbiorze są zarezerwowane dla semantyki specyficznej
dla procesora.

Globalne i słabe symbole różnią się na dwa główne sposoby.

* Kiedy edytor łączenia (ang. link editor) łączy kilka relokacyjnych
 plików obiektowych nie zezwala na istnienie wielu definicji symboli
STB_GLOBAL o tej samej nazwie. Z drugiej stronym jeśli zdefiniowany symbol
globalny istnieje, istnienie symbolu słabego o identycznej nazwie nie powoduje
wystąpienia błędu. Edytor łączenia uznaje globalną definicję i ignoruje
słabe definicje. Podobnie, jeśli wspólny symbol istnieje (np. symbol dla
którego st_shndx zawiera SHN_COMMON), pojawienie się słabego symbolu o tej
samej nazwie nie powoduje błędu. Edytor łączenia honoruje wspólne (ang. common)
definicje i ignoruje słabe.

* Kiedy edytor łączenia przeszukuje biblioteki, rozpakowuje pola które
zawierają definicje niezdefiniowanych symboli globalnych. Definicja
pola może być symbolem słabym lub globalnym. Edytor łączenia nie 
rozpakowuj pól bibliotek (ang. extract archive members) by rozwiązać
niezdefiniowane słabe symbole. Takie symbole posiadają wartość zero. 

W każdej tablicy symboli, wszystkie symbole z wiązaniem STB_LOCAL
mają wyższy priorytet niż symbole słabe i globalne. Ja ,,Sekcje'' wyżej
opisują, pole nagłówka sekcji sh_info dla sekcji tablicy symboli zawiera
indeks tablicy symboli dla pierwszego nielokalnego symbolu.

Typ symbolu zapewnia klasyfikację dla związanej jednostki (ang. entity).

+ Rysunek 1-18: Tablica Symboli, ELF32_ST_TYPE

  Nazwa        Wartość
  ====         =====
  STT_NOTYPE       0
  STT_OBJECT       1
  STT_FUNC         2
  STT_SECTION      3
  STT_FILE         4
  STT_LOPROC      13
  STT_HIPROC      15

* STT_NOTYPE

  Typ symbolu nie jest zdefiniowany.

* STT_OBJECT

  Symbol jest związany z obiektem danych, takim jak zmienna, tablica itd.

* STT_FUNC

  Symbol związany z funkcją lub innym fragmentem wykonywalnego kodu.

* STT_SECTION

  Symbol jest związany z sekcją. Pozycja tablicy symboli tego typu
istnieje przede wszystkim dla relokacji i normalnie posiada wiązanie
STB_LOCAL.

* STT_FILE

  Zgodnie z przyjętymi konwencjami nazwa tego symbolu podaje nazwę podaje 
nazwę pliku źródłowego związanego z plikiem obiektowym. Symbol pliku posiada
wiązanie STB_LOCAL, jego indeks sekcji wynosi SHN_ABS i ma wyższy priorytet
przed innymi symbolami STB_LOCAL w tym pliku, o ile one istnieją.

* od STT_LOPROC do STT_HIPROC

  Wartości w tym domkniętym zbiorze są zarezerwowane dla semantyki
specyficznej dla procesora.

Symbole funkcji (te z typem STT_FUNC) w współdzielonym pliku obiektowym
posiadają specjalne znaczenie. Kiedy inny plik obiektowy odnosi się
do funkcji z współdzielonego obiektu, edytor łączenia automatycznie tworzy
pozycję tablicy procedur łączenia dla symbolu do którego się odnosi. 
Do symboli dla obiektów współdzielonych z typami innymi niż STT_FUNC nie 
będzie można się odnosić automatycznie za pomocą tablicy procedur łączenia
(ang. procedure linkage table). 

Jeśli wartość symbolu odnosi się do specyficznej lokalizacji w środku
sekcji, jego pole indeksu sekcji - st_shndx - zawiera indeks do 
tablicy nagłówków sekcji. Gdy sekcja przemieszcza się podczas relokacji,
wartość symbolu zmienia się również i odnośniki do symbolu wciąż
wskazują do tej samej lokalizacji w programie. Pewne wartości indeksów
sekcji specjalnych posiadają inną semantykę. 

* SHN_ABS

  Symbol posiada absolutną wartość która nie będzie się zmieniać z powodów
relokacji.

* SHN_COMMON

  Symbol oznacza wspólny blok który jeszcze nie został zaalokowany
(przydzielony). Wartość symbolu podaje ograniczenia wypełniania, podobnie
jak pole sh_addralign sekcji. Oznacza to że edytor łączenie przydzieli
dla symbolu pamięć o adresie który jest wielokrotnością st_value. Rozmiar
symbolu podaje ile bajtów będzie potrzebnych.

* SHN_UNDEF
  
  Ten indeks tablicy sekcji oznacza że symbol jest niezdefiniowany. Kiedy
edytor łączenia łączy ten plik obiektowy z innymi które definiują ten symbol, 
odnośniki w tym pliku zostaną połączone z właściwą definicją.

Jak wspomniano wyżej, pozycja tablica symboli dla indeksu 0 (STN_UNDEF) jest
zarezerwowana. Zawiera ona następujące wartości:

+ Rysunek 1-19: Pozycja tablicy symboli: Indeks 0

  Nazwa       Wartość  Uwaga
  ====        =====    ====
  st_name       0      Brak typu
  st_value      0      Wartość zerowa
  st_size       0      Brak rozmiaru
  st_info       0      Brak typu, wiązania lokalne
  st_other      0
  st_shndx  SHN_UNDEF  Brak sekcji


			    Wartości symboli

Pozycja tablicy symboli dla różnych typów plików obiektowych ma nieco
różną interpretację dla pola st_value.

* W plikach relokacyjnych, st_value zawiera ograniczenia dopełniania
(ang. alignment constraints) dla symbolu którego indeks sekcji wynosi
SHN_COMMON.
* W plikach relokacyjnych st_value zawiera ofset dla zdefiniowanego
symbolu (błąd w dokumentacji czy jak? -przyp autora). Oznacza to
że st_value jest ofsetem od początku sekcji identyfikowanej przez st_shndx.
* W plikach wykonywalnych i współdzielonych, st_value zawiera 
adres wirtualny. Aby symbole tych plików były bardziej poręczne dla dynamicznego
linkera, ofset sekcji (interpretacja pliku) podaje drogę do wirtualnego adresu
(interpretacja pamięci) do którego nie ma odnosienia numer sekcji.

Chociaż wartości tablicy symboli posiadają podobne znaczenie dla różnych
plików obiektowych, dane pozwalają na efektywny dostęp dla odpowiednich 
programów.


   ========================== Relokacja  ==========================


Relokacja jest procesem łączenia odnośników do symboli z definicjami 
symboli. Na przykład kiedy prgram wywołuje funkcję, związana z tym instrukcja
call musi przekazać kontrolę pod właściwy adres pod wykonanie. Onnymi słowy 
pliki relokacyjne muszą posiadać informacje o tym jak modyfikować zawartość
ich sekcji, umożliwiając w ten sposób współdzielonym i wykonywalnym plikom
obiektowym trzymać właściwe informacje dla obrazu procesu programu. Te dane
to pozycje (ang. entries) , pola relokacji.

+ Rysunek 1-20: Pozycje relokacji

  typedef struct {
      Elf32_Addr	r_offset;
      Elf32_Word	r_info;
  } Elf32_Rel;

  typedef struct {
      Elf32_Addr	r_offset;
      Elf32_Word	r_info;
      Elf32_Sword	r_addend;
  } Elf32_Rela;

* r_offset

  To pole podaje lokalizację do której odnosi się akcja relokacji.
Dla plików relokacyjnych, wartością tego pola jest ofset od początku sekcji
do jednostki pamięci (storage unit) na której się odbije relokacja.
Dla plików wykonywalnych lub obiektów współdzielonych, wartością jest adres
wirtualny jednostki pamięci dotkniętej relokacją.

* r_info
  
  To pole podaje zarówno indeks tablicy symboli z uznaniem relokacji
która musi być dokonana, jak i typ relokacji mającej być zastosowanej.
Na przykład pozycja relokacji instrukcji call zawierałaby indeks tablicy
symboli dla wołanej funkcji. Jeśli indeks ten ma wartość STN_UNDEF, czyli
indeks niezdefiniowanego symbolu, relokacja używa 0 jako ,,wartości symbolu''.
Typy relokacji są specyficzne dla procesora. Kiedy tekst odnosi się do typu
relokacji pozycji relokacji lub indeksu tablicy symboli, oznacza to rezultat
zastosowania odpowiednio ELF32_R_TYPE lub ELF32_R_SYM do pola r_info pozycji. 
 
    #define ELF32_R_SYM(i)	((i)>>8)
    #define ELF32_R_TYPE(i)	((unsigned char)(i))
    #define ELF32_R_INFO(s, t)	((s)<<8+(unsigned char)(t))

* r_addend

  To pole definiuje stały dodatek (ang. addend) używany do obliczania 
wartości która będzie przechowywana w przemieszczalnym polu.

Jak pokazano wyżej, tylko pozycje Elf32_Rela zawierają z góry określony
dodatek (ang. explocit addend). Pozycje typu Elf32_Rel przechowują 
domnieny dodatek w lokalizacji która będzie modyfikowana. Zależnie od 
architektury procesora, jedna fomra lub druga będzie niezbędna lub bardziej
wygodna. Również implementacja dla jednej maszyny może używać wyłącznie 
jednej formy albo wybierać formę zależnie od kontekstu.

Sekcja relokacji odnosi się do dwóch innych sekcji: tablicy symboli i 
sekcji która będzie modyfikowana. Pola sh_info i sh_link nagłówka sekcji,
opisane wyżej w ,,Sekcjach'', opisują te zależności. Pozycje dla różnych
plików obiektowych posiadają nieco inną interpretację pola r_offset.

* W plikach relokacyjnych, r_offset przechowuje ofset sekcji. Oznacza to
  że sekcja relokacji sama opisuje jak zmodyfikować inną sekcję w pliku;
  ofsety relokacji wyznaczają jednostki pamięci w środku innej sekcji.

* W plikach wykonywalnych i współdzielonych, r_offset zawiera wirtualny adres.
  Aby pozycje relokacji w tych plikach bardziej poręcznych dla dynamicznego
  linkera, ofset sekcji (interpretacja pliku) podaje drogę do adresu 
  wirtualnego (interpretacja pamięci).

Chociaż interpretacja r_offset zmienia się dla różnych plików obiektowych aby
zapewnić efektywny dostęp przez odpowiednie programy, znaczenie typów relokacji
pozostaje takie samo.

			   Typy Relokacji

Pozycje relokacji opisują jak zmieniać następujące instrukcje i pola danych
(numery bitów pojawiają się w dolnych rogach prostokąta).

+ Rysunek 1-21: Pola relokacyjne 

    +---------------------------+
    |          word32           |
   31---------------------------0


* word32

  To definiuje 32bitowe pole zajmujące 4 bajty z dowolnym wypełnianiem. 
Te wartości używają tego samego porządku bajtów jak inne wartości słów
w 32bitowej architektury Intela.

                           3------2------1------0------+
	     0x01020304    |  01  |  02  |  03  |  04  |
                          31------+------+------+------0

Obliczenia poniżej przyjmują że akcje przekształcają plik relokacyjny
w albo wykonywalny albo współdzielony plik obiektowy. Koncepcyjnie
edytor łączenia łączy jeden lub więcej plik relokacyjny by stworzyć
wyjście. Najpierw decyduje jak połączyć i zlokalizować pliki wejściowe,
potem uaktualnia wartości symboli i wreszcie przeprowadza relokacje.
Relokacja w odniesieniu do wykonywalnych lub współdzielonych plików obiektowych
jest podobna i powoduje identyczny rezultat. Opisy poniżej używają następującej
symboliki.

* A

  Oznacza dodatki użyte do obliczenia wartości przemieszczalnych pól. 

* B
 
  Oznacza adres bazowy pod którym współdzielone obiekty zostały załadowane 
podczas wykonania do pamięci. Ogólnie współdzielony plik obiektowy jest
 zbudowany z 0 jako podstawą adresów wirtualnych, ale adresy podczas wykonywania
będą inne.

* G

  Oznacza ofset w globalnej tablicy ofsetów w której  adres symbolu
pozycji relokacji pozostaje podczas wykonywania. Zobacz ,,Tablica Globalnych
Ofsetów'' w części drugiej po więcej informacji.

* GOT

  Oznacza adres tablicy globalnych ofsetów.  Zobacz ,,Tablica Globalnych
Ofsetów'' w części drugiej po więcej informacji.

* L

  Oznacza miejsce (ofset sekcji lub adres) pozycji w tablicy procedur
łączenia dla symbolu.(ang. place (section offset or address) of the procedure
  linkage table entry for a symbol). Pozycja w tablicy procedur łączenia
przekierowuje wywołanie funkcji do właściwego przeznaczenia. Edytor łączenia
buduje początkową tablicę procedur łączenia a dynamiczny linker modyfikuje
pozycje/wpisy/elementy (entries) podczas wykonywania. Zobacz ,,Tablica 
procedur łączenia'' w części drugiej po więcej informacji.

* P
  Oznacz miejsce (ofset w sekcji lub adres) jednostki pamięci która jest
przemieszczana (obliczane za pomocą r_offset).

* S

  Oznacza wartość symbolu którego indeks pozostaje w pozycji/wpisie relokacji.

Wartość r_offset pozycji relokacji wyznacza ofset lub wirtuany adres pierwszego
bajtu jednostki pamięci dotkniętej przez relokację. Typ relokacji podaje które
bity należy zmieniać i jak obliczać ich wartości. Architektura Systemu V używa
tylko pozycji relokacji Elf32_Rel , pole które ma być przemieszczone zawiera
dodatek (ang. field to be relocated holds the addend). W wszystkich przypadkach
dodatek i obliczony rezultat używają tego samego porządku bajtów.

+ Rysunek 1-22: Typy Relokacji

  Nazwa           Wartość Pole   Obliczenian
  ====            =====  =====   ===========
  R_386_NONE        0    żadne   żadne
  R_386_32	    1    word32  S + A
  R_386_PC32	    2    word32  S + A - P
  R_386_GOT32	    3    word32  G + A - P
  R_386_PLT32	    4    word32  L + A - P
  R_386_COPY	    5    żadne   żadne
  R_386_GLOB_DAT    6    word32  S
  R_386_JMP_SLOT    7    word32  S
  R_386_RELATIVE    8    word32  B + A
  R_386_GOTOFF	    9    word32  S + A - GOT
  R_386_GOTPC	   10    word32  GOT + A - P

Niektóre typy relokacji posiadają semantykę wymykającą się prostym obliczeniom.

* R_386_GOT32

  Ten typ relokacji oblicza odległość od podstawy tablicy globalnych ofsetów
do pozycji symbolu w tablicy globalnych ofsetów. Dodatkowo instruuje edytor
łączenia  by zbudował tablicę globalnych ofsetów.

* R_386_PLT32

  Ten typ relokacji oblicza adres pozycji w tablicy procedury łączenia dla 
symbolu i dodatkowo poucza edytor łączenia by zbudował tablicę procedur 
łączenia.

* R_386_COPY

  Edytor łączenia tworzy ten typ relokacji dla dynamicznego łączenia.
Jego pole ofset odnosi się do lokalizacji w zapisywalnym segmencie.
Indeks tablicy symboli definiuje symbol który powinien istnieć zarówno w
 bieżącym pliku obiektowym i w współdzielonym obiekcie. Podczas wykonywania
dynamiczny linker kopiuje dane związane z symbolami obiektu współdzielonego
do lokalizacji wyspecyfikowanej przez ofset. 

* R_386_GLOB_DAT
  
  Ten typ relokacji jest używany do ustawienia wpisu tablicy globalnych ofsetów
na adres wyspecyfikowanego symbolu. Specjalny typ relokacji pozwala zadecydować
o stosunku między symbolami a pozycjami tablicy globalnych ofsetów.

* R_386_JMP_SLOT {*}

  Edytor łączenia tworzy ten typ relokacji dla dynamicznego łączenia.
Jego pole ofset podaje lokalizację wpisu d tablicy procedur łączenia.
Dynamiczny linker modyfikuje wpis/pozycję w tablicy procedur łączenia
by przekazać kontrolę adresowi wyznaczonego obiektu (zobacz też 
,,Tablica Procedur Łączenia'' w części drugiej).

* R_386_RELATIVE

  Edytor łączenia tworzy ten typ relokacji dla dynamicznego łączenia.
 Jego pole ofset podaje lokalizację w środku współdzielonego obiektu
który zawiera wartość reprezentującą względny adres. Dynamiczny linker
oblicza odpowiedni adres wirtualny poprzez dodanie wirtualnego adresu
pod którym współdzielony obiekt był załadowany pod adres względny. Pozycje
relokacji dla tego typu muszą zawierać zero dla indeksu tablicy symboli.


* R_386_GOTOFF

  Ten typ relokacji oblicza różnicę między wartością symbolu i adresem
tablicy globalnych ofsetów. Dodatkowo instruuje edytor łączenia by 
zbudował tablicę globalnych ofsetów.

* R_386_GOTPC

  Ten typ relokacji przypomina R_386_PC32, poza tym że używa adresu 
tablicy globalnych ofsetów w obliczeniach. Symbol do którego odnosi się
ta relokacja to zwykle _GLOBAL_OFFSET_TABLE_, co dodatkowo poucza edytor
łączenia by zbudował tablicę globalnych ofsetów.

   ________________________________________________________________


		2. ŁADOWANIE PROGRAMU I DYNAMICZNE ŁĄCZENIE

   ________________________________________________________________


   ========================= Wprowadzenie =========================


Część 2 opisuje informacje dotyczące plików obiektowych i akcje systemu
które tworzą działające programy. Niektóre informacje tu podane odnoszą się
do wszystkich systemów, inne są specyficzne dla konkretnego procesora.

Wykonywalne i współdzielone pliki obiektowe statycznie reprezentują program.
Aby wykonać taki program, system używa plików aby utworzyć dynamiczną
reprezentację programu, albo inaczej obraz procesu. Obraz procesu
posiada segmenty zawierające jego tekst (kod), dane, stos itd. Główne
punkty w tej części omawiają następujące tematy:

* Nagłówek programu. Ten punkt dopełnia część pierwszą, opisując struktury
pliku obiektowego które odnoszą się bezpośrednio do wykonania programu.
  Główna struktura danych, tablica nagłówka programu, lokalizuje obrazy
segmentu wewnątrz pliku i zawiera inne informacje niezbędne do stworzenia obrazu
pamięci programu.
* Ładowanie programu. System mając plik obiektowy musi załadować go do pamięci
aby program mógł wystartować.
* Dynamiczne łączenie. Gdy system załaduje program, musi skompletować
obraz procesu poprzez rozwiązanie odniesień do symboli pomiędzy plikami
obiektowymi składającymi się na proces.

ZAUWAŻ: Istnieją konwencje nazywania dla stałych ELF które posiadają
zdefiniowane zasięgi procesorów (ang have specified processor ranges). Nazwy
takie jak DT_, PT_ dla rozszerzeń specyficznych dla procesora zawierają nazwę
procesora: np. DT_M32_SPECIAL. Już istniejące rozszerzenia dla konkretnych
procesorów niezgodne z tą konwencją będą jednak wspierane.


		       Istniejące Rozszerzenia
		       =======================
			      DT_JMP_REL


   ======================== Nagłówek programu =====================


Tablica nagłówka programu pliku obiektowego lub współdzielonego jest
tablicą struktur z których każda opisuje segment lub inną informację której
system potrzebuje aby przygotować program do odpalenia. Segment pliku 
obiektowego zawiera jedną lub więcej sekcji, tak jak niżej jest to opisane w 
punkcie ,,Zawartość Segmentu''. Nagłówki programu są znaczące tylko dla 
współdzielonych i wykonywalnych plików obiektowych. Plik definiuje rozmiar
własnego nagłówka programu za pomocą pól nagłówka ELF : e_phnum i e_phentsize
[Zobacz też ,,Nagłówek ELF'' w części pierwszej].

+ Rysunek 2-1: Nagłówek Programu 

  typedef struct {
      Elf32_Word	p_type;
      Elf32_Off		p_offset;
      Elf32_Addr	p_vaddr;
      Elf32_Addr	p_paddr;
      Elf32_Word	p_filesz;
      Elf32_Word	p_memsz;
      Elf32_Word	p_flags;
      Elf32_Word	p_align;
  } Elf32_Phdr;

* p_type

  To pole opisuje jaki rodzaj segmentu opisuje ten element tablicy lub jak
interpretować informache elementu tablicy. Wartości typów i ich znaczenie
opisane są niżej.

* p_offset

  To pole podaje ofset od początku pliku na którym znajduje się pierwszy
bajt segmentu.

* p_vaddr

  To pole podaje wirtualny adres pod którym pierwszy bajt segmentu znajduje 
się w pamięci.

* p_paddr

  Na systemach dla których odpowiednie jest fizyczne adresowanie, to pole
jest zarezerwowane dla fizycznego adresu segmentu. Ponieważ System V 
ignoruje fizyczne adresowanie dla programów użytkownika/użytkowych, to 
pole posiade niezdefiniowaną zawartość dla plików wykonywalnych i obiektów
współdzielonych.

* p_filesz

  To pole podaje liczbę bajtów w obrazie segmentu w pliku. Może wynosić zero.

* p_memsz

  To pole podaje liczbę bajtów w obrazie segmentu w pamięci. Może wynosić zero.

* p_flags

  To pole podaje flagi stosowane dla segmentu. Zdefiniowane wartości flag
pojawiają się niżej.

* p_align

  Tak jak to później w tej części opisuje punkt ,,Ładowanie Programu'', 
ładowalne segmenty procesu muszą posiadać (ang. congruent) wartości dla 
p_vaddr i p_offset, modulo rozmiar strony. To pole podaje wartość dla której
segmenty są wyrównywane w pamięci i pliku. Wartości 0 i 1 oznaczają że nie jest
potrzebne wyrównywanie. W innych przypadkach p_align powinna być dodatnią, 
całkowitą potęgą dwójki, a p_vaddr powinno się równać p_offset modulo
p_align.
 
Niektóre wpisy/pozycje opisują segmenty procesu; inne podają dodatkowe
informacje i nie dotyczą obrazu procesu. Zdefiniowane pozycje mogą pojawić się
w dowolnym porządku, za wyjątkiem przypadków opisanych poniżej. Poniżej opisane
są wartości typów segmentów - inne wartości są zarezerwowane dla użycia w 
przyszłości.


+ Rysunek 2-2: Typy segmentów, p_type

  Nazwa            Wartość
  ====             =====
  PT_NULL              0
  PT_LOAD              1
  PT_DYNAMIC           2
  PT_INTERP            3
  PT_NOTE              4
  PT_SHLIB             5
  PT_PHDR              6
  PT_LOPROC   0x70000000
  PT_HIPROC   0x7fffffff

* PT_NULL

  Element tablicy jest nieużywany; inne wartości pola są niezdefiniowane.
ten typ pozwala tablicy nagłówku programu posiadać ignorowane wpisy.

* PT_LOAD

  Element tablicy podaje ładowalny segment, opisany przez p_filesz i 
p_memsz. Bajty z początku pliku są mapowane do początku segmentu pamięci.
Jeśli rozmiar pamięci segmentu (p_memsz jest większy niż rozmiar pliku
(p_filesz), dodatkowe bajty z definicji zawierają wartość zero i następują
po zainicjalizowanym obszarze segmentu. Rozmiar pliku nie może być większy
niż rozmiar pamięci. Wpisy łądowalnych segmentów w tablicy nagłówku programu
pojawiają się w porządku rosnącym, uporządkowane wg pola P_vaddr.

* PT_DYNAMIC

  Element tablicy specyfikuje informacje tyczące dynamicznego łaczenia. Zobacz
też punkt ,,Sekcje Dynamiczne'' poniżej jeśli chcesz uzyskać więcej informacji.

* PT_INTERP

  Element tablicy specyfikuje lokalizację i rozmiar nazwy ścieżki do 
programu wywoływanego jako interpreter; mazwa ta zakończona jest zerem.
Ten typ segmentu ma znaczenie tylko i wyłącznie dla plików wykonywalnych
(chociaż może się pojawić również w obiektach współdzielonych). Może też
pojawić się więcej niż raz w pliku. Jeśli jest obecny, musi poprzedzać 
jakąkolwiek pozycję/wpis ładowalnego segmentu. Zobacz punkt ,,Interpreter
Programu'' poniżej w celu uzyskania więcej informacji.

* PT_NOTE
  
  Element tablicy specyfikuje lokalizację i rozmiar pomocniczej informacji.
Zobacz też punkt ,,Sekcje Uwag'' poniżej po więcej szczegółów.

* PT_SHLIB
  
  Ten typ segmentu jest zarezerwowany ale nie posiada zdefiniowanej
semantyki. Programy zawierające element tablicy tego typu nie są zgodne 
z ABI.

* PT_PHDR

  Element tablicy, jeśli obecny, podaje lokalizację i rozmiar samej
tablicy nagłówku programu (ang. location and size program header table
itself), zarówno w pliku jak i w obrazie pamięci programu. ten typ
segmentu nie może pojawić się więcej niż raz w pliku, co więcej, może pojawić
tylko wtedy gdy tablica nagłówka programu jest częścią obrazu pamięci programu.
Jeśli jest obecny, musi poprzedzać jakikolwiek wpis/pozycję (ang entry)
łądowalnego segmentu. Zobacz też punkt ,,Interpreter Programu'' aby uzyskać
więcej informacji.

* PT_LOPROC through PT_HIPROC

  Wartości w tym domkniętym zbiorze są zarezerwowane dla semantyki specyficznej
dla procesora.

ZAUWAŻ: O ile nie jest to jawnie wymagane gdzie indziej, wszystkie typy
segmentów nagłówka programu są opcjonalne. To znaczy tablica nagłówka 
programu może zawierać tylke te elementy stosowne do jej zawartości.


			     Adres Bazowy

Obiektowe pliki współdzielone i wykonywalne posiadają adres bazowy, który
jest najniższym wirtualnym adresem związanym z obrazem pamięci pliku
obiektowego programu. Używa się adresu bazowego do relokacji obrazu
pamięci programu podczas dynamicznego łączenia.

Adres bazowy pliku wykonywalnego i współdzielonego jest obliczany podczas
wykonywania z trzech wartości: adresu załadowania pamięci, maksymalnego
rozmiaru strony, i najniższego adresu wirtualnego segmentu ładowalnego programu.
Tak jak to opisuje punkt ,,Ładowanie Programu'' w tym rozdziale, adresy
wirtualne mogą nie reprezentować właściwych adresów wirtualnych obrazu pamięci
programu. Aby obliczyć adres podstawowy, należy odnaleźć adres pamięci 
związany z najmniejszą wartością p_vaddr dla segmentu PT_LOAD. Następnie 
otrzymuje się adres bazowy obcinajać adres w pamięci do najbliższej
wielokrotności maksymalnego rozmiaru strony pamięci. Zależnie od rodzaju pliku
który jest ładowany do pamięci, adres pamięci może lub nie odpowiadać
wartościom p_vaddr. 

Tak jak opisuje to w części 1 punkt ,,Sekcje'', sekcja .bss posiada typ
SHT_NOBITS. Chociaż nie zajmuje przestrzeni w pliku, odnosi się do obrazu
pamięci segmentu. Zwykle te niezainicjalizowane dane pozostają na końcu segmentu
w ten sposób czyniąc p_memsz większy niż p_filesz w związanym elemencie 
nagłówka programu.


			     Sekcja Uwag 

Czasami producent lub twórca systemu potrzebuje oznaczyć plik obiektowy
za pomocą specjalnej informacji którą inne programy będą sprawdzać dla
zgodności (ang for conformance and compatibility etc). Sekcje typu SHT_NOTE
i elementy nagłówka programu typu PT_NOTE mogą być używane właśnie do tego celu.
Informacja ta w sekcjach i elementach nagłówka programu zawiera jakąkolwiek
liczbę pozycji, z których każda jest tablicą czterobajtowych słów w formacie
procesora docelowego. Etykiety pojawiające się niżej służą do pomocy przy
objaśnianiu organizacji tych informacji, ale nie są częścią specyfikacji. 

+ Rysunek 2-3: Uwagi

  namesz
  descsz
  type
  name ...
  desc ...

* namesz i name

  Pierwsze namesz bajtów w polu ,,name'' (nazwa) zawiera zakończoną zerem
znakową reprezentację właściciela lub oryginalnego twórcy pozycji. Nie ma
żadnego sformalizowanego mechanizmu który pozwalałby unikać konfliktów nazw.
Zgodnie z konwencją producenci używają swoich własnych nazw, takich jak
,,Kompania komputerowa XYZ'' jako identyfikatorów. Jeżeli nie jest obecna żadna
nazwa, namesz zawiera zero. Jeśli jest to konieczne, wykonuje się dopełnianie
(ang. padding) aby zapewnić 4-bajtowe wyrównywanie (ang. alignment).   
Takie dopełnianie nie jest zawarte w namesz.

* descsz i desc

  Pierwsze descsz bajtów i w polu ,,desc'' (opis) zawiera deskryptor uwagi.
ABI nie zawiera żadnych ograniczeń na zawartość deskryptora. Jeśli nie 
istnieje taki deskryptor, descsz  zwiera zero. Jeśli jest to konieczne, wykonuje
się dopełnianie (ang. padding) aby zapewnić 4-bajtowe wyrównywanie
(ang. alignment). Takie dopełnianie nie jest zawarte w descsz.

* type

  To słowo podaje interpretację deskryptora. Każdy twórca kontroluje swoje
własne typy. Mogą istnieć wielokrotne interpretacje wartości pojedyńczego typu.
Dlatego też program musi rozpoznawać zarówno typ jak i nazwę aby zrozumieć
deskryptor. Obecnie typy muszą być nieujemne. ABI ine definiuje co oznacza
deskryptor.

Aby to zilustrować, następujący segment uwag posiada dwie pozycje:

+ Rysunek 2-4: Przykład segmentu uwag

           +0   +1   +2   +3
          -------------------
  namesz           7
  descsz           0      Brak deskryptora
    type           1
    name   X    Y    Z    spc 
           C    o    \0   pad
  namesz           7
  descsz           8
    type           3
    name   X    Y    Z    spc
           C    o    \0   pad
    desc         word0
                 word1

ZAUWAŻ: System rezerwuje uwagi bez nazw (namesz=0) i z zerową długością 
nazwy (name[0]=='\0') ale obecnie nie definiuje żadnych typów. Wszystkie
inne nazwy muszą zawierać co najmniej jeden jeden znak różny od znaku pustego.

ZAUWAŻ: Uwagi są opcjonalne. Obecność tych informacji nie odbija się
na zgodności programu z ABI, o ile ta informacja nie zmienia zachowania
programu. Jeśli tak się dzieje, program nie jest zgodny z ABI i posiada
niezdefiniowane zachowanie.


   ======================= Ładowanie Programu =====================

Gdy system tworzy lub powiększa obraz procesu, logicznie kopiuje
segment pliku do segmentu pamięci wirtualnej. Kiedy - i jeśli - system
fizycznie przeczyta plik zależy od zachowania programu, obciążenia systemu 
(ang. system load) itd. Proves nie wymaga fizycznej strony dopóki 
odnosi się do stron logicznych podczas wykonywania i procesy powszechnie
nie odnoszą się do wielu stron (ang. leave may pages unreferenced) 
Dlatego też opóźnienia fizycznego odczytu często ich nie obchodzi (ang obviates
them) opprawiając wydajność systemu. Aby otrzymać efektywność w praktyce, pliki
wykonywalne i współdzielone muszą posiadać obrazy segmentów których 
ofsety plików i adresy wirtualne są (ang. congruent) modulo rozmiar strony.

Adresy wirtualne i ofsety plików dla segmentów architektury SYSTEMU V są
(ang. congruent) modulo 4KB (0x1000) lub większej potęgi dwójki. Ponieważ
4 KB jest maksymalnym rozmiatem strony, pliku pozostaną wygodne i nadające się
dla stronicowania niezależnie od rozmiaru fizycznej strony. 

+ Rysunek 2-5: Plik wykonywalny

           Ofset pliku   Plik                  Adres Wirtualny
           ===========   ====                  ===============
                     0   Nagłówek ELF
  Tablica nagłówka programu
                         Inne informacje  
                 0x100   Segment Kodu          0x8048100
                         ...
                         0x2be00 bajtów        0x8073eff
               0x2bf00   Segment danych        0x8074f00
                         ...
                         0x4e00 bajtów         0x8079cff
               0x30d00   Inne informacje  
                         ...

+ Rysunek 2-6: Segmenty nagłówka programu

  Pole      Tekst(kod)   Dane
  ======    ====         ====
  p_type    PT_LOAD      PT_LOAD
  p_offset  0x100	 0x2bf00
  p_vaddr   0x8048100	 0x8074f00
  p_paddr   unspecified	 unspecified
  p_filesz  0x2be00	 0x4e00
  p_memsz   0x2be00	 0x5e24
  p_flags   PF_R+PF_X    PF_R+PF_W+PF_X
  p_align   0x1000	 0x1000

Chociaż ofsety przykładowego pliku i adresy wirtualne są (ang congruent)
modulo 4 KB dla zarówno tekstu (kodu) jak i danych, do czterech stron
plikowych zawiera nieczyste (? ang. impure ?) dane i tekst (zależnie od
rozmiaru strony i rozmiaru bloku systemu).

* Pierwsza strona kodu zawiera nagłówek ELF, nagłówek programu i inne informacje
* Ostatnia strona kodu zawiera kopię początku danych.
* Pierwsza strona danych zawiera kopię początku tekstu.
* Ostatnia strona danych może zawierać informację o pliku nie mające
zastosowania dla działającego procesu.

Logicznie, system wymusza pozwolenia na dostęp do pamięci (ang, memory
permissions) tak jak gdyby każdy segment był kompletny i osobny. Adresy
segmentów są dostosowywane by zapewnić dla każdej logicznej strony w 
przestrzeni adresowej istnieje osobny zbiór zezwoleń. W przykładzie 
powyżej obszar pliku zawierający koniec tekstu i początek danych byłby
zamapowany dwukrotnie; na jednym wirtualnym adresie dla kodu i osobnym
adresie wirtualnym dla danych.

Koniec segmentu danych wymaga specjalnego traktowania dla niezainicjalizowanych
danych, które system definiuje jako startujące z zerową zawartością. Stąd jeśli
ostania strona danych pliku zawiera informacje nie w logicznej stronie pamięci
dodatkowe dane muszą być ustawione na zeroom a nie na nieznane zawartości 
pliku wykonywalnego. ,,Nieczystości'' w pozostałych trzech stronach nie są
logiczną częścią obrazu procesu. Nie jest zdefiniowane czy system je kasuje.
Obraz dla tego programu wyglądałby następująco, przyjmując 4 KB strony.

+ Rysunek 2-7: Segmenty obrazu procesu

  Adresy wirtualne Zawartość           Segment
  ===============  ========            =======
        0x8048000  Dopełnienie nagłówka Tekst
                   0x100 bajtów
        0x8048100  Segment kodu 
                   ...
                   0x2be00 bajtów
        0x8073f00  Dopełnienie danych
                   0x100 bajtów
        0x8074000  Dopełnienie kodu    Dane
                   0xf00 bajtów
        0x8074f00  Segment danych
                   ...
                   0x4e00 bajtów
        0x8079d00  Niezainicjalizowane dane
                   0x1024 zerowych bajtów
        0x807ad24  Dopełnienie strony
                   0x2dc zerowych bajtów

Jeden z aspektów ładowania segmentów różni się pomiędzy plikami wykonywalnymi
i obiektami współdzielonymi. Pliku wykonywalne zazwyczaj zawierają absolutny
kod. Aby pozwolić procesowi na poprawne wykonywanie się, segmenty muszą 
przebywać pod wirtualnymi adresami użytymi do zbudowania pliku 
wykonywalnego. Stąd system używa wartości p_vaddr niezmienionych jako
adresów wirtualnych

Z drugiej strony, segmenty obiektów współdzielonych zazwyczaj zawierają
kod niezależny od pozycji. Pozwala to wirtualnym adresom segmentów
zmieniać się między jednym procesem a drugim, bez zakłócania zachowania
wykonywania. Chociaż system wybiera adresy wirtualne dla indywidualnych procesów
zarządza względnymi pozycjami segmentów. Ponieważ kod niezależny od pozycji
używa względnego adresowania pomiędzy segmentami, różnica pomiędzy wirtualnymi 
adresami w pamięci musi się zgadzać z różnicą pomiędzy wirtualnymi adresami w 
pliku. Następująca tablica pokazuje możliwe przydziały wirtualnych adresów dla
obiektów współdzielonych, ilustrując stałe względne pozycje. Tablica ilustruje
również obliczenia bazowych adresów.

+ Rysunek 2-8: Przykład adresów segmentów współdzielonych obiektów.

  Źródło            Kod         Data  Adres bazowy 
  =====             ====        ====  ============
  Plik             0x200     0x2a400           0x0
  Proces 1    0x80000200  0x8002a400    0x80000000
  Proces 2    0x80081200  0x800ab400    0x80081000
  Proces 3    0x900c0200  0x900ea400    0x900c0000
  Proces 4    0x900c6200  0x900f0400    0x900c6000


   ======================= Dynamiczne łączenie ====================


			 Interpreter Programu

Plik wykonywalny może mieć jeden element nagłówka programu typu
PT_INTERP. Podczas exec(BA_OS), system otrzymuje ścieżkę z segmentu
PT_INTERP i tworzy obraz procesu inicjującego z segmentu pliku 
interpretera: to znaczy, zamiast używać obrazu segmentu oryginalnego
pliku wykonywalnego, system tworzy obraz pamięci z interpretera. Potem
na interpreterze spoczywa odpowiedzialność za przejęcie kontroli od
systemu i zapewnienie środowiska dla programu użytkowego.

Interpreter otrzymuje kontrole w jeden z dwóch sposobów. Po pierwsze,
może otrzymać deskryptor pliku do odczytania pliku wykonywalnego,
zaczynając od początku. Może używać tego deskryptora pliku by odczytywać
i/lub mapować segmenty pliku wykonywalnego do pamięci. Po drugie, zależnie
od formatu pliku wykonywalnego, system może załadować plik wykonywalny
do pamięci zamiast podania interpretorowi deskryptora pliku. Z możliwym
możliwym wyłączeniem deskryptora pliku, stan początkowy procesu
interpretera dopasowuje to co otrzymałby pliku
wykonywalny. Sam interpreter nie może wymagać innego interpretera.
Interpreter może być plikiem wykonywalnym lub obiektem współdzielonym.

* obiekt współdzielony (w normalnym przypadku) jest ładowany jako
niezależny od pozycji, z adresami które mogą się różnić między 
jednym procesem a drugim; system tworzy segment w obszarze dynamicznego
segmentu używanym przez mmap(KE_OS) i jemu podobne usługi. 
Konsekwetnie (w efekcie? ang consequently) również interpreter 
współdzielonego obiektu nie spowoduje konfliktu z oryginalnym
adresem segmentu pliku wykonywalnego.

* Plik wykonywalny jest ładowany pod dopasowane adresy; system tworzy
jego segmenty używając wirtualnych adresów z tablicy nagłówka programu.
W efekcie adresy wirtualne interpretera pliku wykonywalnego mogą
kolidować z pierwszym plikiem wykonywalnyml interpreter jest odpowiedzialny
za rozwiązywanie takich konfliktów.


			    Dynamiczny Linker

Podczas budowania pliku wykonywalnego który używa dynamicznego łączenia,
edytor łączenia dodaje element nagłówka programu typu PT_INTERP do
pliku wykonywalnego, w ten sposób powiadamiając system by wywoływał
dynamicznego linkera jak interpreter programu.

ZAUWAŻ: lokalizacja dynamicznych linkerów dostarczanych przez system
jest specyficzna dla procesora.

Exec(BA_OS) oraz dynamiczny linker współpracują aby stworzyć obraz procesu
dla programu, co wymaga następujących akcji:

* Dodania segmentu pamięci pliku wykonywalnego do obrazu procesu;
* Dodanie segmentu pamięci wspołdzielonego obiektu do obrazu procesu;
* Wykonania relokacji dla pliku wykonywalnego i jego współdzielonych
obiektów;
* Zamknięcia deskryptora pliku użytego do przeczytania
pliku wykonywalnego, o ile jakiś został dostarczony dynamicznemu linkerowi;
* Przekazania kontroli programowi, czyniąc to tak jak gdyby program
otrzymał kontrolę bezpośrednio od exec(BA_OS).

Edytor łączenia również konstruuje różne dane które są potrzebne
dynamicznemu linkerowi przy wykonywalnych i współdzielonych plikach
obiektowych. Tak jak to wyżej było pokazane w ,,Nagłówku programu'',
ten dane pozostają w segmencie wykonywalnym, czyniąc je dostępnymi
podczas wykonywania. (Jeszcze raz, przypomnienie (ang. recall)
dokładnej zawartości segmentu jest specyficzne dla procesora. Zobacz
dodatek o procesorach dla pełnej informacji). 

* Sekcja .dynamic o typie SHT_DYNAMIC zawiera rozmaite dane. Struktura
przebywająca na początku sekcji zawiera adresy innych informacji dla
dynamicznego łączenia.

* Sekcja .hash o typie SHT_HASH zawiera tablicę haszową symboli.

* Sekcje .got i .plt o typie SHT_PROGBITS zawierają dwie oddzielne
tablice: tablice globalnego ofsetu i tablicę procedur łączenia.
Sekcje poniżej wyjaśniają jak dynamiczny linker używa ich i zmienia 
tablice aby stworzyć obraz pamięci dla plików obiektowych.

Ponieważ każdy zgodny z ABI program importuje podstawowe usługi
systemowe z biblioteki współdzielonych, dynamiczny linker bierze udział
w każdym wykonaniu programu zgodnego z ABI.

Tak jak to wyjaśnia punkt ,,Ładowanie programu w dodatku o procesorach,
obiekty mogą zajmować wirtualne adresy które różnią się od adresów 
zapisanych w tablicy nagłówka programu w pliku. Dynamiczny linker
relokuje obraz pamięci, uaktualniając bezwzględne adresy zanim 
aplikacja otrzyma kontrolę. Chociaż wartości bezwzględne adresów 
byłyby poprawne gdyby biblioteki były ładowane pod adresem zdefiniowanym
w tablicy nagłówka programu, tak normalnie się nie robi.

Jeżeli środowisko procesu [zobacz exec(BA_OS)] zawiera zmienną nazwaną
LD_BIND_NOW z niepustą wartością, dynamiczny linker podejmuje wszelkie
relokacje zanim przekaże kontrolę programowi. Na przykład wszystkie
ustawienia zmiennej środowiskowej poniżej spowodowałyby to zachowanie.

* LD_BIND_NOW=1
* LD_BIND_NOW=on
* LD_BIND_NOW=off

W przeciwnym razie LD_BIND_NOW albo nie pojawia się w środowisku albo 
posiada pustą wartość. Dynamiczny linker może ,,leniwie'' wartościować
pozycje tablicy procedur łączenia, w ten sposób unikając rozwiązywania
symboli i nakładu związanego z relokacją dla funkcji, które nie są
wywoływane. Zobacz też ,,Tablica łączenia procedur'' w tej części po 
więcej informacji.


			   Sekcje dynamiczne 

Jeśli plik obiektowy bierze udział w dynamicznym łączeniu, jego
tablica nagłówka programu będzie zawierał element typu PT_DYNAMIC.
Ten ,,segment'' zawiera sekcję .dynamic. Specjalny symbol, _DYNAMIC,
zaznacza sekcję, który zawiera (tlumacz: sekcja czy symbol??) tablicę
następujących struktur:

+ Rysunek 2-9: Struktury Dynamiczne 

  typedef struct {
      Elf32_Sword d_tag;
      union {
          Elf32_Sword	d_val;
          Elf32_Addr	d_ptr;
      } d_un;
  } Elf32_Dyn;

  extern Elf32_Dyn _DYNAMIC[];

Dla każdego obiektu tego typu, d_tag kontroluje interpretację d_un.

* d_val

  Te obiekty Elf32_Word reprezentują wartości całkowite z różnymi
interpretacjami.

* d_ptr

  Te obiekty Elf32_Addr reprezentują wirtualne adresy programu. Jak 
poprzednio wspomniano, adresy wirtualne pliku mogą być różne od
adresów wirtaulnych w pamięci podczas wykonywania. Podczas interpretowania
adresów zawartych w sekcji dynamicznej, dynamiczny linker oblicza 
właściwe adresy, oparte na oryginalnych wartościach w pliku i 
adresu bazowego w pamięci. Dla spójności, pliku nie zawierając pozycji
relokacji do ,,poprawiania'' adresów w strukturze dynamicznej.

Następująca tablica wymienia (ang. tag) wymagania dla obiektowych
plików wykonywalnych i współdzielonych. Jeśli tag jest zaznaczony jako
,,obowiązkowy'', wtedy tablica dynamicznego łączenia dla każdego 
pliku zgodnego z ABI musi posiadać wpis tego typu. Tak samo ,,opcjonalnie''
oznacza że wpis dla taga może się pojawić ale nie jest wymagany.

+ Rysunek 2-10: Tagi dynamicznej tablicy, d_tag

  Nazwa              Wartość d_un        Wykonywalny  Współdzielony
  ====               =====  ====         ==========   =============
  DT_NULL                0  ignorownany  obowiązkowy  obowiązkowy
  DT_NEEDED		 1  d_val	 opcjonalny   opcjonalny
  DT_PLTRELSZ		 2  d_val	 opcjonalny   opcjonalny
  DT_PLTGOT		 3  d_ptr	 opcjonalny   opcjonalny
  DT_HASH		 4  d_ptr	 obowiązkowy  obowiązkowy
  DT_STRTAB		 5  d_ptr	 obowiązkowy  obowiązkowy
  DT_SYMTAB		 6  d_ptr	 obowiązkowy  obowiązkowy
  DT_RELA		 7  d_ptr	 obowiązkowy  opcjonalny
  DT_RELASZ		 8  d_val	 obowiązkowy  opcjonalny
  DT_RELAENT		 9  d_val	 obowiązkowy  opcjonalny
  DT_STRSZ		10  d_val 	 obowiązkowy  obowiązkowy
  DT_SYMENT		11  d_val	 obowiązkowy  obowiązkowy	
  DT_INIT		12  d_ptr	 opcjonalny   opcjonalny
  DT_FINI		13  d_ptr	 opcjonalny   opcjonalny
  DT_SONAME		14  d_val	 ignorowany   opcjonalny
  DT_RPATH		15  d_val	 opcjonalny   ignorowany
  DT_SYMBOLIC		16  ignored	 ignorowany   opcjonalny
  DT_REL		17  d_ptr	 obowiązkowy  opcjonalny
  DT_RELSZ		18  d_val	 obowiązkowy  opcjonalny
  DT_RELENT		19  d_val        obowiązkowy  opcjonalny
  DT_PLTREL		20  d_val	 opcjonalny   opcjonalny
  DT_DEBUG		21  d_ptr	 opcjonalny   ignorowany
  DT_TEXTREL		22  ignored      opcjonalny   opcjonalny
  DT_JMPREL		23  d_ptr        opcjonalny   opcjonalny
  DT_LOPROC     0x70000000  niezdefiniowany ---------------------
  DT_HIPROC     0x7fffffff  niezdefiniowany ---------------------

* DT_NULL

  Wpis z tagiem DT_NULL oznacza koniec tablicy _DYNAMIC

* DT_NEEDED
  
  Ten element zawiera ofset tablicy łańcuchów zakończonych znakiem
pustym łańcuchów, podających nazwy potrzebnych bibliotek. Ofset
jest indeksem do tablicy zawartej w pozycji DT_STRTAB. Zobacz 
,,Zależności obiektów współdzielonych'' dla więcej informacji o tych
nazwach. Tablica dynamiczna może zawierać wielokrotne wpisy z tymi typami.
Porządek tych wpisów jest znaczący, chociaż ich pozycja względem
innych typów nie jest.

* DT_PLTRELSZ

  Ten element zawiera totalny rozmiar w bajtach pozycji relokacji 
związanych z tablicą procedur łączenia. Jeśli wpis o typir
DT_JMPREL jest obecny, musi mu towarzyszyć DT_PLTRELSZ.

* DT_PLTGOT

  Ten element zawiera adres związany z tablicą procedur łączenia i/lun
tablicą globalnych ofsetów. Zobacz punkt dodatku o procesorach po więcej
szczegóły.

* DT_HASH

  Ten element zawiera adres haszowej tablicy symboli, opisanej w
,,Tablicy Haszowej''. Ta tablica haszowa odnosi sie do tablicy
symboli wskazywanej/do której się odnosi element DT_SYMTAB.

* DT_STRTAB

  Ten element zawiera adresy tablicy nazw, opisanej w części pierwszej.
Nazwy symboli, nazwy bibliotek i inne łańcuchy znajdują się w tej 
tablicy.

* DT_SYMTAB

  Ten element zawiera adresy tablicy symboli, opisanej w części pierwszej
z wpisami Elf32_Sym dla 32-bitowej klasy plików.

* DT_RELA
  
  Ten element zawiera adres tablicy relokacji, opisanej w części 1.
Wpisy w tej tablicy posiadają z góry znane (ang explicit addends)
dodatki, takie jak Elf32_Rela dla 32-bitowej klasy plików.
Plik obiektowy może posiadać wiele sekcji relokacji. Podczas budowania
tablicy relokacji dla współdzielonego lub wykonywalnego pliku 
obiektowego, edytor łączenia (ang. catenates... może concatenates?) 
formuje z tych sekcji pojedyncza tablicę. Chociaż sekcje pozostają
niezależne w pliku obiektowym, dynamiczny linker widzi pojedyńczą tablicę.
Kiedy dynamiczny linker tworzy obraz procesu  dla pliku wykonywalnego
albo dodaje współdzielony obiekt do obrazu procesu, czyta tablicę relokacji
i podejmuje związane akcje. Jeśli ten element jest obecnym struktura
dynamiczna musi również posiadać elementy DT_RELASZ i DT_RELAENT. Kiedy
relokacja jest ,,obowiązkowa'' dla pliku, albo DT_RELA albo DT_REL mogą
się pojawić (obydwa są dozwolone, lcze nie wymagane).

* DT_RELASZ

  Ten element zawiera totalny rozmiar w bajtach tablicy relokacji
DT_RELA.

* DT_RELAENT
  
  Ten element zawiera rozmiar w bajtach wpisu DT_RELA relokacji

* DT_STRSZ
  
  Ten element zawiera rozmiar w bajtach tablicy nazw.

* DT_SYMENT

  Ten element zawiera rozmiar w bajtach wpisu tablicy symboli.

* DT_INIT
  
  Ten element zawiera adres funkcji inicjalizacyjnej, omówionej w 
punkcie ,,Funkcje Inicjalizacyjne i Kończące'' poniżej.

* DT_FINI

  Ten element zawiera adres funkcji kończącej omówionej w punkcie
,,Funkcje Inicjalizujące i konczące''.

* DT_SONAME
  
  Ten element zawiera ofset tablicy nazw/łańcuchów zawierającej
łańcuchy zakończone znakiem pustym, podające nazwę współdzielonego
obiektu. Ofset jest indeksem do tablicy zapisanej w wpisie DT_STRTAB.
Zobacz punkt ,,Zależności w Plikach Obiektowych'' poniżej aby uzyskać
więcej informacji na ten temat. 

* DT_RPATH
  
  Ten element zawiera ofset tablicy nazw/łańcuchów zawierającej
łańcuchy zakończone znakiem pustym, podające nazwę ścieżkę przeszukiwań
bibliotek, omówioną w ,,Zależnościach w Plikach Obiektowych''. Ofset jest
indeksem do tablicy zapisanej w wpisie DT_STRTAB.

* DT_SYMBOLIC

  Obecność tego elementu w bibliotece współdzielonych obiektów zmienia
algorytm dynamicznego linkera rozwiązywania symbolów dla odniesień 
w środku biblioteki. Zamiast zaczynać przeszukiwanie w środku pliku
wykonywalnego, dynamiczny linker zaczyna od samego obiektu 
współdzielonego. Jeśli symbol do którego nastąpiło odniesienie nie zawiera
się w obiekcie współdzielonym, dynamiczny linker zaczyna przeszukiwać
pliki wykonywalne i inne obiekty współdzielone w zwykły sposób.

* DT_REL

  Ten element jest podobny do DT_RELA, poza tym że jego tablica posiada
dodatki nie wiadome z góry (ang. implicit), takie jak Elf32_Rel dla klasy
plików 32-bitowych. Jeśli ten element jest obecny, struktura dynamiczna
musi posiadać również elementy DT_RELSZ i DT_RELENT.

* DT_RELSZ

  Ten element zawiera rozmiar w bajtach tablicy relokacji DT_REL. 

* DT_RELENT

  Ten element zawiera rozmiar w bajtach wpisu relokacji DT_REL. 

* DT_PLTREL

  To pole definiuje typ wpisu relokacji do którego odnosi się
tablica procedur łączenia. Wartość d_val zawiera DT_REL lub DT_RELA,
zależnie od kontekstu. Wszystkie relokacje w tablicy procedur łączenia
muszą używać tej samej relokacji (od tłumacza: typu relokacji jak sądzę).

* DT_DEBUG

  To pole jest używana do debuggingu. Jego zawartość nie jest zdefiniowana
przez ABI. Programy które dostają się do tego wpisu nie są zgodne z ABI.

* DT_TEXTREL

  Nieobecność tego pola oznacza że żaden wpis relokacji nie powinien 
powodować modyfikacji niezapisywalnego segmentu, tak jak wyspecyfikowano
w zezwoleniach do segmentu w tablicy nagłówka programu. Jeśli pole to 
jest obecne, jeden lub więcej wpis relokacji może zażądać modyfikacje
do niezapisywalnego segmentu, i odpowiednio może przygotowywać 
dynamiczny linker.

* DT_JMPREL

  Jeśli obecne, to pole pozycji d_prt przechowuje adres pozycji
relokacji związane wyłącznie z tablicą procedur łączenia. Separowanie
tych pozycji relokacji pozwala dynamicznemu linkerowi ignorować je 
podczas inicjalizacji procesu, o ile jest włączone ,,leniwe'' wiązanie.
Jeśli to pole jest obecne, odnośne pozycje typu DT_PLTRELSZ i DT_PLTREL
muszą również być obecne.

* od DT_LOPROC do DT_HIPROC

  Wartości w tym domkniętym zbiorze są zarezerwowane dla semantyki
specyficznej dla procesora.

Za wyjątkiem elementu DT_NULL na końcu tablicy i względnego porządku
elementów DT_NEEDED, wpisy mogą pojawiać się w dowolnym porządku.
Wartości tagów nie pojawiające się w tablicy są zarezerwowane.


		      Zależności w obiektach współdzielonych

Kiedy edytor łączenia przetwarza biblitekę (ang. archive library),
ekstrahuje pola biblioteki i kopiuje je do wynikowego pliku
obiektowego. Te statycznie wkompilowane usługi są dostępne podczas
wykonywania bez potrzeby korzystania z usług dynamicznego linkera.
Obiekty współdzielone dostarczają również usług i dynamiczny linker
musi dołączyc odpowiedni współdzielony plik obiektowy to obrazu pliku
do wykonania. Stąd wspołdzielone i wykonywalne pliki obiektowe
opisują ich spsecyficzne zależności.

Kiedy dynamiczny linker tworzy segmenty pamięci dla pliku obiektowego,
zależności (zapisane w wpisie DT_NEEDED struktury dynamicznej) mowią jakie
obiekty współdzielone są potrzebne do wsparcia usług procesu (?). 
Poprzez powtarzające łączenie zależności i współdzielonych obiektów do 
których się one odnoszą, dynamiczny linker buduje kompletny 
obraz procesu. Podczas rozwiązywania symbolicznych odnośników, dynamiczny
linker przegląda tablicę symboli za pomocą przeszukiwania wszerz.
To znaczy najpierw patrzy na tablicę symboli samego programu, potem na 
tablice symboli wpisów w DT_NEEDED (zgodnie z ich uporządkowaniem), potem
na wpisy drugiego poziomu DT_NEEDED (od tłumacza tj. wymagane przez te
z DT_NEEDED pierwszego poziomu) itd. Współdzielone pliki obiektowe muszą
być odczytywalne przez proces - inne zezwolenia nie są wymagane.

ZAUWAŻ: Nawet kiedy do wpółdzielonego obiektu  istnieje wiele odwołań
w liście zależności, dynamiczny linker dołączy obiekt do procesu tylko raz.

Nazwy w liście zależności są kopiami albo łańcuchów DT_SONAME 
albo nazwami ścieżek współdzielonych obiektów użytych di zbudowania pliku
obiektowego. Na przykład, jeśli edytor łączenia zbuduje plik wykonywalny 
używając jednego obiektu współdzielonego z wpisem DT_SONAME jako lib1 i
innej biblioteki obiektów współdzielonych w nazwą ścieżki /usr/lib/lib2,
plik wykonywalny zawierać będzie lib1 i /usr/lib/lib2 w swojej liście
zależności.

Jeśli nazwa obiektu współdzielonego zawiera jeden lub więcej znaków
"/" (szleszy jak to mawiał doktor Stefanowski :) ) - gdziekolwiek w nazwie,
tak jak /usr/lib/lib2 jak powyżej albo katalog/plik, dynamiczny linker
używa tej nazwy bezpośrednio jako nazwy ścieżki. Jeśli nazwa nie ma znaków
"/", tak jak wyżej lib1, trzy udogodnienia definiują przeszukiwania
ścieżki obiektów współdzielonych, wg następującej procedury:

* Po pierwsze, tag dynamicznej tablicy DT_RPATH może podać łańcuch
który zawiera listę katalogów, rozdzielanych przez dwukropek (:). Na 
przykład, łańcuch /home/dir/lib:/home/dir2/lib: powiadamia dynamicznego
linkera by przeszukiwął najpierw katalog /home/dir/lib a następnie
/home/dir2/lib, i wreszcie katalog domowy aby odnaleźć zależności.
* Po drugie, zmienna w środowisku procesu LD_LIBRARY_PATH [zobacz 
exec(BA_OS)] może zawierać listę katalogów jak wyżej, opcjonalnie 
zakończonych średnikiem i kolejną listę katalogów. Następujące 
wartości byłyby równoważne do poprzedniego przykładu:
    LD_LIBRARY_PATH=/home/dir/lib:/home/dir2/lib:
    LD_LIBRARY_PATH=/home/dir/lib;/home/dir2/lib:
    LD_LIBRARY_PATH=/home/dir/lib:/home/dir2/lib:;
Wszystkie katalogi LD_LIBRARY_PATH są przeszukiwane po tych z DT_RPATH.
Chociaż niektóre programy (takie jak edytor łączenia) traktują 
listy przed i po średniku różnie, dynamiczny linker tak nie czyni.
Dynamiczny linker akceptuje notację z średnikiem z semantyką opisaną
powyżej.
*Wreszcie, jeśli pozostałe dwie grupy katalogów nie będą zawierać pożądanej
biblioteki, dynamiczny linker przeszukuje /usr/lib.

ZAUWAŻ: Dla bezpieczeństwa, dynamiczny linker ignoruje 
środowiskowe ustawienia przeszukiwania, takie jak LD_LIBRABRY_PATH dla
programów typu set-user i set-group ID. Jednakże przeszukuje katalogi
wyszczególnione w DT_RPATH i /usr/lib.


			 Tablica globalnych ofsetów

Kod zależny od pozycji w ogólności nie może zawierać absolutnych 
wirtualnych adresów. Tablica globalnych ofsetów zawiera absolutne
adresy w prywatnych danych, w ten sposób czyniąc adresy dostępnymi
bez niweczenia niezależności od pozycji i współdzielenia kodu programu.
Program odwołuje się do swojej tablicy globalnych ofsetów używając
adresowania niezależnego od pozycji i wyciągając absolutne wartości, w 
ten sposób zmieniając odwołania/odnośniki niezależne od pozycji do
bezwzględnych/absolutnych lokalizacji.

Początkowo, tablica globalnych ofsetów zawiera informacje wymagane
przez swoje wpisy relokacji [zobacz ,,Relokacja'' w części pierwszej].
Gdy system stworzy segmenty pamięci dla ładowalnego pliku obiektowego, 
dynamiczny linker przetwarza wpisy relokacji, z których niektóre będą
typu R_386_GLOB_DAT odnoszącego się do tablicy globalnych ofsetów.
Dynamiczny linker znajduje związane wartości symboli, oblicza ich
absolutne wartości i ustawia odpowiednie wpisy w tablicy pamięci na
właściwe wartości. Chociaż absolutne adresy są nieznane kiedy edytor 
łączenia buduje plik obiektowy, dynamiczny linker wie adresy wszystkich
segmentów pamięci i stąd umie obliczyć absolutną wartość zawartych tam
symboli.

Jeśli program wymaga bezpośredniego dostępu do absolutnych adresów
symbolu, ten symbol będzie posiadał wpis w tablicy globalnych ofsetów
(Zaraz, zaraz.. a może to jest globalna tablica ofsetów?). Ponieważ
pliki wykonywalne i współdzielone obiekty posiadają oddzielne
tablice globalnych ofsetów adresy symboli mogą pojawić się w kilku
tablicach. Dynamiczny linker przetwarza wszystkie relokacje w tych
tablicach globalnych ofsetów zanim przekazuje kontrolę do jakiegokolwiek
kodu w obrazie procesu, w ten sposób zapewniając dostępność absolutnych
adresów podczas wykonywania.

Wpis w tablicy jest zarezerwowany do trzymania adresów dynamicznej 
struktury, do której odwołuje się za pomocą symbolu _DYNAMIC. To pozwala
programowi - takiemu jak dynamiczny linker - odnajdywać swoje własne
struktury dynamiczne jeszcze nie przetwarzając własnch wpisów/pozycji
relokacji. Jest to specjalnie ważne dla dynamicznego linkera, ponieważ
musi on najpierw zainicjować się bez polegania na tym, że inne programy
zrelokują jego obraz pamięci (?). W 32bitowej architekturze intela, wpisy
pierwszy i drugi w tablicy globalnych ofsetów (globalnej tablicy ofsetów?
ang. global offset table) są również zarezerwawane i opisuje je punkt
,,Tablica Procedur Łączenia'' poniżej.

System może wybrać różne adresy segmentów pamięci dla tych samych obiektów
współdzielonych w różnych programach; może nawet wybrać różne adresy
bibliotek dla różnych wykonań tego samego programu. Jednakże segmenty pamięci
nie zmieniają adresów od czasu stworzenia obrazu procesu. Tak długo jak 
długo istnieje proces, jego segmenty pamięci pozostają pod raz 
dopasowanymi adresami wirtualnymi.

Format i interpretacja tablicy globalnych ofsetów są zależne od procesora.
Dla 32-bitowej architektury Intela, do dostępu do tablicy może zostać
użyty symbol _GLOBAL_OFFSET_TABLE_.

+ Rysunek 2-11: Tablica globalnych ofsetów

  extern Elf32_Addr _GLOBAL_OFFSET_TABLE_[];

Symbol _GLOBAL_OFFSET_TABLE_  może przebywać w środku sekcji .got, 
pozwalając zarówno na ujemne i dodatnie ,,zapisy'' do tablicy
adresów.


		       Tablica procedur łączenia

Tak samo jak tablica globalnych ofsetów  przekształca adresy 
niezależne od pozycji w bezwzględne lokalizacje, tak samo tablica
procedur łączenia przekształca niezależne od pozycji w absolutne
lokalizacje. (zmienić w tablice łączenia procedur!). Edytor łączenia
nie może rozwiązać przekazywania wykonywania (takie jak wołania
funkcji) pomiędzy jednym plikiem wykonywalnym lub współdzielonym a innym.
Na skutek tego edytor łączenia aranżuje sytuację w której program
przekazuje kontrolę do wpisów w tablicy łączenia procedur (ang.
the link editor arranges to have the program transfer control to
procedure linkage table).  W architekturze Systemu V, tablice łączenia
procedur przebywają w  współdzielonym segmencie kodu, ale używają
adresów z prywatnej globalnej tablicy ofsetów. Dynamiczny linker
determinuje absolutne adresy przeznaczenia i odpowiednio modyfikuje obraz
pamięci globalnej tablicy ofsetów. W ten sposób dynamiczny linker może
przekształcać wpisy bez niweczenia niezależności od pozycji i 
współdzielenia kodu/tekstu programu. Pliki wykonywalne i współdzielone
pliki obiektowe posiadają rozdzielne tablice łączenia procedur. 

+ Rysunek 2-12: Bezwględna tablica procedur łączenia {*}

  .PLT0:pushl   got_plus_4
        jmp     *got_plus_8
        nop; nop
        nop; nop
  .PLT1:jmp     *name1_in_GOT
        pushl   $offset
        jmp     .PLT0@PC
  .PLT2:jmp     *name2_in_GOT
        pushl   $offset
        jmp     .PLT0@PC
        ...

+ Rysunek 2-13: Tablica procedur łączenia niezależna od pozycji.

  .PLT0:pushl   4(%ebx)
        jmp     *8(%ebx)
        nop; nop
        nop; nop
  .PLT1:jmp     *name1@GOT(%ebx)
        pushl   $offset
        jmp     .PLT0@PC
  .PLT2:jmp     *name2@GOT(%ebx)
        pushl   $offset
        jmp     .PLT0@PC
        ...

ZAUWAŻ: Tak jak to pokazuje rysunek, instrukcje tablicy procedur łączenia
używają innego trybu adresowania operandów dla kodu absolutnego i zależnego
od pozycji. Jest to jednak bez znaczenia, gdyz ich interfejs do linkera
pozostaje taki sam.

Postępując według kroków poniżej, dynamiczny linker i program
,,współpracują'' aby rozwiązać symboliczne odniesienia poprzez tablicę
procedur łączenia i tablicę globalnych ofsetów.

1. Podczas pierwszego tworzenia obrazu pamięci programu, dynamiczny
linker ustawia drugi i trzeci wpis w globalnej tablicy ofsetów na
specjalne wartości. Kroki niżej wyjaśniają więcej na temat tych wartości.
2. Jeśli tablica łączenia procedur jest niezależna od pozycji, adres
globalnej tablicy ofsetów musi przebywać w %ebx. Każdy współdzielony
plik obiektowy w obrazie procesu posiada swoją własną tablicę łączenia
procedur i kontrola przechodzi do wpisu w tablicy łączenia procedur tylko
w środku tego samego pliku obiektowego. Stąd funkcja dokonująca wywołania
(ang. calling function) jest odpowiedzialna za ustawienie bazowego
rejestru  globalnej tablicy ofsetów zanim odwoła się do  wpisu w tablicy
łączenia procedur.
3. Przyjmijmy dla przykładu że program wywołuje name1, co przekazuje
kontrolę do nazwy/etykiety/symbolu (ang. label) .PLT1.
4. Pierwsza instrukcja powoduje skok do adresu w pozycji w globalnej
tablicy ofsetów dla name1. Początkowo, globalna tanlica ofsetów
przetrzymuje adres następnej instrukcji pushl a nie właściwy adres name1.
5. Program odkłada ofset relokacji (dalej po prostu ofset) na stos. 
Ofset relokacji jest 32-bitowym nieujemnym ofsetem w tablicy relokacji.
Wyznaczona pozycja/wpis relokacji będzie posiadać typ R_386_JMP_SLOT,
a jej ofset będzie specyfikować wpis w globalnej tablicy ofsetów użyty
w poprzedniej instrukcji jmp. Wpis relokacji będzie również zawierać
indeks tablicy symboli, w ten sposób zawiadamiając dynamicznego linkera
do jakiego symbolu się odwołujemy, w tym przypadku name1.

6. Po odłożeniu ofsetu relokacji, program wykonuje skok do .PLT0, pierwszego
wpisu w tablicy łączenia procedur. Instrukcja pushl odkłada
wartość drugiego wpisu w globalnej tablicy ofsetów (got_plus_4 albo
4(%ebx) na stosie, w ten sposób podając dynamicznemu linkerowi słowo 
identyfikującej informacji. Następnie program wykonuje skok do adresu w
trzecim wpisie globalnej tablicy ofsetów (got_plus_8 albo 8(%ebx), co 
przekazuje kontrolę dynamicznemu linkerowi.
7. Kiedy dynamiczny linker otrzymuje kontrolę, czyści (ang. unwinds) stos,
patrzy na wyznaczoną pozycję relokacji, odnajduje wartość symbolu, zachowuje
,,prawdziwy'' adres dla name1 w globalnej tablicy ofsetów i przekazuje 
kontrolę do pożądanego przeznaczenia.
8. Następne wykonywanie wpisów w tablicy łączenia procedur będą już
odwoływać się bezpośrednio do name1, bez wołania dynamicznego linkera po
raz drugi. Oznacza to, że instrukcja jmp w .PLT1 przekaże kontrolę do
name1, zamiast ,,przelatwywania przez'' (ang falling through) instrukcję
pushl.

Zmienna środowiskowa LD_BIND_NOW może zmienić zachowanie dynamicznego 
linkera. Jeśli jej wartość nie jest pusta, dynamiczny linkera wartościuje
wpisy tablicy procedur łączenia zanim przekaże programowi kontrolę. Oznacza
to że dynamiczny linker przetwarza pozycje relokacji o typie
R_386_JMP_SLOT podczas inicjalizacji procesu. W innym przypadku dynamiczny
linker wartościuje wpisy w tablicy łączenia procedur w ,,leniwy'' sposób,
opóźniając rozwiązywanie symbolów i relokację do pierwszego wykonania
wpisu tablicy.
ZAUWAŻ: ,,Leniwe'' wiązanie zazwyczaj poprawia całkowitą wydajność
aplikacji, ponieważ nieużywane symbole nie powodują niepotrzebnego
nadmiaru (ang overhead) przy dynamicznym łączeniu. Jednakże mogą
pojawić się dwie sytuacje w których ,,leniwe'' wiązanie może 
być niepożądane. Po pierwsze, pierwsze odwołanie do funkcji
współdzielonego obiektu może zabrać więcej czasu niż następne wołania, 
ponieważ dynamiczny linker przechwytuje wołanie aby rozwiązać symbol.
Niektóre aplikacje nie mogą tolerować takiego nieprzywidywalnego 
zachowania. Po drugie, jeśli pojawi się błąd i dynamiczny linker nie 
będzie mógł rozwiązać symbolu, dynamiczny linker zakończy program.
Podczas ,,leinwego'' wiązania może to zdarzyć się w dowololnym czasie.
I znowu, niektóre aplikacje nie mogą takiego zachowanie tolerować.
Poprzez wyłączenie ,,leniwego'' wiązania, dynamiczny linker narzuca 
pojawianie się wszystkich błędów podczas inicjalizacji procesu, zanim
aplikacja otrzyma kontrolę.


			     Tablica Haszująca 

Tablica haszująca obiektów Elf32_Word wspiera dostęp do tablicy symboli.
Nazwy/oznaczenia (ang.labels) pojawiają się niżej aby wyjaśnić organizację
tablicy haszowej, ale nie są one częścią specyfikacji.

+ Rysunek 2-14: Haszująca tablica symboli

  nbucket
  nchain
  bucket[0]
  ...
  bucket[nbucket - 1]
  chain[0]
  ...
  chain[nchain - 1]

Tablica ,,koszyk'' (ang bucket array) zawiera nbucket wpisów, a tablica
łańcuchowa (chain array) zawiera nchain wpisów. Indeksy zaczynają się od
zera. Zarówno ,,koszyk'' jak i ,,łańcuch'' zawierają indeksy tablicy symboli
Tablica ,,łańcuch'' zawiera wpisy równoległe do tablicy symboli. Liczba
wpisów w tablicy symboli powinna byc równa nchain; tak więc indeksy
tablicy symboli akceptują również wpisów w tablicy ,,łańcuch''.
Funkcja haszująca, pokazana niżej, na wejściu otrzymuje nazwę symbolu
i zwraca wartość która może zostać użyta do obliczenia indeksu ,,koszyka''.
Tak więc jeśli funkcja haszująca zwróci wartość x dla nazwy,
bucket[x%nbucket] podaje indeks, y, do zarówno tablicy symboli jak i tablicy
,,łańcuch''. Jeżeli wpis w tablicy symboli nie odpowiada temu który
chcieliśmy znaleźć, chain[y] podaje następny wpis w tablicy symboli z 
taką samą wartością haszową. Można w ten sposób podążać za łączami 
z tablicy ,,łańcuch'' (chain) dopóki albo wpis w tablicy symboli zawiera
pożądaną nazwę albo wpis w tablicy ,,łańcuch'' zawiera wartość STN_UNDEF.

+ Rysunek 2-15: Funkcja haszująca

  unsigned long
  elf_hash(const unsigned char *name)
  {
      unsigned long       h = 0, g;
  
      while (*name) {
          h = (h << 4) + *name++;
          if (g = h & 0xf0000000)
              h ^= g >> 24;
          h &= ~g;
      }
      return h;
  }


	       Funkcje Inicjalizujące i Kończące       

Gdy dynamiczny linker zbuduje obraz procesu i przeprowadzi relokację, 
każdy obiekt współdzielony otrzymuje możliwość wykonania pewnego kodu
inicjującego. Te funkcje inicjalizujące są wywoływane bez żadnego
określonego porządku, ale wszystkie inicjalizacyjne funkcje obiektów
współdzielonych wykonują się zanim plik wykonywalny otrzyma kontrolę.

Podobnie, obiekty współdzielone mogą mieć funkcje kończące, które
są wykonywane za pomocą mechanizmu atexit(BA_OS) gdy proces
podstawowy zacznie sekwencję zakończenia. I znowu porządek w jakim
dynamiczny linker wywoła te funkcje jest niezdefiniowany.

Obiekty współdzielone wyznaczają swoje funkcje inicjalizujące i kończące
za pomocą wpisów w DT_INIT i DT_FINI w strukturze dynamicznej opisanej
w punkcie ,,Sekcje Dynamiczne'' powyżej. Zazwyczaj kod dla tych
funkcji znajduje się w sekcjach .init i .fini, wspomnianych w 
,,Sekcjach'' w części pierwszej.

ZAUWAŻ: Chociaż atexit(BA_OS) przetwarzanie na zakończenie zwykle
zostanie wykonane, nie ma żadnej gwarancji że zostanie wykonane po
śmierci procesu. W szczególności proces nie wykona przetwarzania
na zakończenie (kończącego, terminującego) jeśli wywoła _exit 
[zobacz exit(BA_OS)] lub jeśli proces umrze ponieważ otrzyma sygnał
którego nie przechwycił lub nie zignorował.

   ________________________________________________________________


			     3. Biblioteka C

   ________________________________________________________________


   ========================== Biblioteka C ========================


Biblioteka C, libc, zawiera wszystkie symbole zawarte w libsys i na dodatek
zawiera funkcje wypisane w następnych dwóch tablicach. Pierwsz tablica
wypisuje funkcje z standardu ANSI C.

+ Rysunek 3-1: Zawartość libc, Nazwy bez synonimów    

  abort        fputc        isprint      putc         strncmp
  abs	       fputs        ispunct      putchar      strncpy
  asctime      fread        isspace      puts         strpbrk
  atof	       freopen      isupper      qsort        strrchr
  atoi	       frexp        isxdigit     raise        strspn
  atol	       fscanf       labs         rand         strstr
  bsearch      fseek        ldexp        rewind       strtod
  clearerr     fsetpos      ldiv         scanf        strtok
  clock	       ftell        localtime    setbuf       strtol
  ctime	       fwrite       longjmp      setjmp       strtoul
  difftime     getc         mblen        setvbuf      tmpfile
  div	       getchar      mbstowcs     sprintf      tmpnam
  fclose       getenv       mbtowc       srand        tolower
  feof	       gets         memchr       sscanf       toupper
  ferror       gmtime       memcmp       strcat       ungetc
  fflush       isalnum      memcpy       strchr       vfprintf
  fgetc	       isalpha      memmove      strcmp       vprintf
  fgetpos      iscntrl      memset       strcpy       vsprintf
  fgets	       isdigit      mktime       strcspn      wcstombs
  fopen	       isgraph      perror       strlen       wctomb
  fprintf      islower      printf       strncat    

Dodatkowo, libc zawiera następujące usługi:     

+ Rysunek 3-2: Zawartość libc, nazwy z synonimami.

  __assert     getdate      lockf **     sleep        tell ** 
  cfgetispeed  getopt       lsearch      strdup       tempnam
  cfgetospeed  getpass      memccpy      swab         tfind
  cfsetispeed  getsubopt    mkfifo       tcdrain      toascii
  cfsetospeed  getw         mktemp       tcflow       _tolower
  ctermid      hcreate      monitor      tcflush      tsearch
  cuserid      hdestroy     nftw         tcgetattr    _toupper
  dup2	       hsearch      nl_langinfo  tcgetpgrp    twalk
  fdopen       isascii      pclose       tcgetsid     tzset
  __filbuf     isatty       popen        tcsendbreak  _xftw
  fileno       isnan        putenv       tcsetattr    
  __flsbuf     isnand **    putw         tcsetpgrp    
  fmtmsg **    lfind        setlabel     tdelete      

  ** = Funkcja jest na poziomie 2 w  SVID wydaniu 3 i stąd również na
       poziomie 2 w ABI.

Poza symbolami wymienionymi w tablicy ,,Z synonimami'' powyżej,
synonimy w formie _ istnieją dla pozycji  które nie są
wymienione z podkreśleniem poprzedzającym ich nazwę. Stąd libc zawiera
na przykład zarówno getopt jak i _getopt.

Z funkcji powyżej wymienonych, następujące nie są gdzie indziej
zdefiniowane:

int __filbuf(FILE *f);
 	Ta funkcja zwraca następny znak w wejściu dla f, zapełniają jego
(swój? ang. its) bufor jeśli potrzeba. Zwraca EOF jeśli pojawił się błąd.

int __flsbuf(int x, FILE *f);
	Ta funkcja opróżnia znaki dla wejścia dla f tak jakby było wywołane
putc(x,f) i następnie dołącza wartość x do wynikowego strumienia
wyjściowego. Zwraca EOF jeśli pojawił się błąd i x wpw.

int _xftw(int, char *, int (*)(char *, struct stat *, int), int);
	Odwołania do funkcji ftw(BA_LIB) są podmapowane pod tą funkcję
gdy aplikacje są kompilowane. Ta funkcja jest identyczna jak ftw(BA_LIB)
za wyjątkiem tego że _xftw() bierze wstawiony pierwszy argument, który 
musi posiadać wartość 2.

Zobacz inne punkty w tym rozdziale po więcej udogodnień SVID, ANSI C 
i POSIXa. Zobacz ,,Interfes Danych systemowych'' później w tym rozdziale
po więcej informacji. (EEE? od tłumacza - ale rozdział właśnie się urywa!)


			 Globalne symbole danych

Biblioteka libc wymaga aby były zdefiniowane pewne zewnętrzne symbole
danych aby jej funkcje działały poprawnie. Wszystkie symbole danych
wymagane dla biblioteki libsys muszą zostać zapewnione przez libc,
tak samo jak symbole wymienione w tablicy poniżej.

Dla formalnej deklaracji obiektów danych reprezentowanych przez te
symbole zobacz w Definicji Interfejsu Systemu V, Wydanie Trzecie lub
w punkcie ,,Definicje danych'' rodziału szóstego dla odpowiedniego
dodatku o procesorze do ABI Systemu V.

Dla wpisów w następujących tabelach które są w formie -_,
obydwa symbole w każdej parze reprezentują te same dane. Synonimy z 
podkreśleniami są dostarczane dla zgodności z standardem ANSI C.

+ Rysunek 3-3: Zawartość libc, Globalne Zewnętrzne symbole danych

  getdate_err		optarg
  _getdate_err		opterr
  __iob			optind
	 		optopt