Ma być nowy wspaniały świat. Atarki z procesorem 65c816, 4/8/16 MHz, 16 MB RAM-u, cuda wianki. Wymyśliłem, że do tego trzeba może trochę odświeżyć format pliku binarnego, bo $FFFF to zawsze była żenada, a teraz tym bardziej. W końcu jest XXI wiek  ;)

Kiedyś już taki format wymyśliłem, nawet wypuściłem w tym SI 2.06 czy coś takiego. Po latach stwierdzam, że to chyba dobry wynalazek, tym bardziej że jeszcze nad tym popracowałem. Założenia:

1) binaria mają być relokowalne;
2) ma nie być ograniczeń dla programisty, tj. taki plik powinien być zdolny do przechowania każdego możliwego rodzaju kodu na 6502;
3) ma pozwalać na ładowanie plików do rozszerzonej pamięci 65c816.

Format pliku:

bajty 0-3: sygnatura formatu, $52, $45, $4c, $31 (tekst: "REL1")
bajty 4-5: flagi

Flagi (znaczenie gdy = 1):

bit 0 - TSR - program ma jest rezydentem
bit 1 - RUN - uruchomić od offsetu RUNAD
bit 2 - INIT - uruchomić od offsetu INITAD
bit 3 - LWORD - wszystkie dalsze słowa nagłówka 24-bit (16-bit w przeciwnym razie)

bity 4-7: MEMFLG - zakodowany rodzaj pamięci, do którego program ma *najchętniej* być załadowany: 0 - podstawowa ($0000-$FFFF), 1 - rozszerzona ($010000-$FFFFFF), reszta wartości zarezerwowana.

bit 8 - APAGE (Align to PAGE ;-)) - adres ładowania wyrównać w górę do najbliższej wolnej granicy stron.
bit 9 - ABANK - adres ładowania wyrównać w górę do najbliższej wolnej granicy banków.
bity 10-15 - zarezerwowane for future extensions.

Dalszy wygląd nagłówka zależy od wartości bitu 3 we flagach, jak napisano wyżej. W każdym razie:

słowo 0 - długość bloku binarnego programu (nie licząc nagłówka i fixupów)
słowo 1 - długość bloku fixupów 16-bitowych (offsety z zakresu 0-65535), zero jeśli takowego bloku nie ma.
słowo 2 - długość bloku fixupów 24-bitowych (offsety większe od 65535), zero jeśli takowego nie ma
słowo 3 - na razie zarezerwowane
słowo 4 - RUNAD - offset (liczony od początku kodu programu), od którego program należy uruchomić; uruchomienie następuje skokiem JMP tylko wtedy, kiedy flaga RUN w nagłówku jest ustawiona. Rejestry CPU osmiobitowe przy tym myślę.
słowo 5 - INITAD - offset (liczony od początku kodu program), od którego program należy uruchomić; uruchomienie następuje skokiem JSR tylko wtedy, kiedy flaga INIT w nagłówku jest ustawiona. Program ma wrócić przez RTS oddając status zwykłą metodą (czyli LDY #$01 na przykład). Rejestry CPU jak wyżej.
bajt - długość następującego stringu (albo zero, kiedy go nie ma)
string - opcjonalna informacja tekstowa o długości do 254 znaków, zakończona zerem (czyli razem do 255 bajtów).

Dalej jedzie segment binarny o długości jak wykazano w słowie 0. Segment jest jeden i ciągły, bo chyba nie ma sensu robić wielu jak program i tak jest relokowalny.

Po nim fixupy. Fixup to są po prostu dwa bajty (albo trzy, patrz wyżej) offsetu wewnątrz pliku (licząc od początku kodu), gdzie jest adres absolutny odnoszący się do wnętrza programu; np. argument wewnętrznego skoku JSR. Do słowa znajdującego się w miejscu wskazanym przez fixupa dodajemy adres ładowania programu (czyli np. wartość MEMLO).

Teraz: wiadomo, że adresy w Atari są w kolejności młodszy/starszy; fixup wskazuje oczywiście bajt młodszy, loader ma po uzupełnieniu go sam zwiększyć offset o 1 i fiksnąć też bajt starszy.

Ale, w takim układzie oczywiście nie przejdzie konstrukcja następująca, chyba wszyscy wiedzą czemu:

    lda #<label+1
    ldx #>label+1
...
label   .by "tu cośtam",0    

Do załatwienia tego służy flaga APAGE w nagłówku: program jest ładowany zawsze od początku granicy stron, co oznacza, że młodsze bajty wszystkich adresów pozostają zawsze niezmienne, i że przy fixupowaniu trzeba zmieniać tylko bajty starsze. W takim układzie fixupy pokazują właśnie na nie i loader po ich uzupełnieniu nie ma już niczego kombinować.

Napisałem dzisiaj loader do tego, który powinien działać pod Spartą oraz DOS II+/D, a poza tym program, który przerabia binaria wypuszczone przez np. MAE na ten nowy format, pozwala na ustawianie wszystkich flag z linii komend itede.

W formacie tym będzie SysInfo 2.08, to jest jedyna metoda, żeby program pozwalał sobie załadować tapetę, kiedy jest wystarczająco dużo pamięci, oraz żeby dalej działał, kiedy nie jest.

Uwagi?

KMK
? HEX$(6670358)

2

No, pomysł ciekawy, jeśli się przyjmie. Taka mała rewolucja francuska. Przez jakiś czas soft musiałby być wypuszczany chyba w obu formatach binarnych...

> bit 8 - APAGE

Apage Satanas??? :?

> Dalej jedzie segment binarny o długości jak wykazano w słowie 0. Segment jest jeden i ciągły, bo chyba nie ma sensu robić wielu jak program i tak jest relokowalny.

Nie wiem, ale może nie nakładać takich ograniczeń?

> Napisałem dzisiaj loader do tego, który powinien działać pod Spartą oraz DOS II+/D...

Trzebaby jeszcze dorzucić mimimum MyDOS, oraz jakiś loader typu ChaosLoader. Ja bym poprosił jeszcze XDosa. :)

A teraz niech się wypowiedzą koderzy.

3

Boje sie troche zabierac glos po proznicy, bo zdaje sobie sprawe, ze dokladnie sobie ten format przemyslales i nie wiem, czy moja krytyka moze miec jakakolwiek konstruktywna wartosc, ale uwazam, ze troche mu brakuje do "wymarzonego" formatu. Pierwsza sprawa: relokacja. Mysle, ze pomysl z wyrownaniem do granicy strony to raczej obejscie, a nie rozwiazanie problemu jakim mamy z mnogoscia trybow adresowania. Dodatkowo nie doczytalem (przeoczylem?) jak relokator odroznia argument 2-bajtowy (np. wewnetrzne jsr) od 1-bajtowego (np. wspomniane lda #<costam). Druga sprawa jaka jak narazie zauwazylem, to obecnosc tylko jednego bloku binarnego programu. Jak na XXI wiek to nie jest zbyt rewolucyjne rozwiazanie. Juz od niepametnych czasow na maszynach 16/32 bit obecnosc wielu relokowalnych segmentow jest standardem i wg. mnie wielkim ulatwieniem pracy. Pisze to badzo subiektywnie, gdyz zaczynam uzywac asemblera ca65 z wieloma segmentami i dla mnie to dosc naturalne. Moje spostrzezenia sa zreszta oparte na tym artykule. Jest tam zawartych kilka (nie wszystkie) ciekawych spostrzezen.

4

> bit 8 - APAGE

Apage Satanas??? :?

He, he, exactly.

Dalej jedzie segment binarny o długości jak wykazano w słowie 0. Segment jest jeden i ciągły, bo chyba nie ma sensu robić wielu jak program i tak jest relokowalny.

Nie wiem, ale może nie nakładać takich ograniczeń?

No nie bardzo sobie wyobrażam, po co takie oddzielne segmenty kodu (tak samo jak w pliku $FFFF) miałyby być i co z nimi praktycznie robić. Jeśli i tak ładujemy na adres MEMLO i w okolice, to struktura pliku taka, że porcja tu, porcja tam traci sens.

Napisałem dzisiaj loader do tego, który powinien działać pod Spartą oraz DOS II+/D...

Trzebaby jeszcze dorzucić mimimum MyDOS, oraz jakiś loader typu ChaosLoader. Ja bym poprosił jeszcze XDosa. :)

Rzecz w tym, że loader jest w postaci programu o oryginalnej nazwie exec.com, który działa tak jak x.com Sparty X - czyli wymaga linii komend. SysInfo będzie miało oddzielny loader dla DOS-ów bez linii komend, ale ten loader będzie po prostu ładował na sztywno SI.REL z bieżącego katalogu ...

A XDosa w życiu nie widziałem na oczy. Wszystko zależy od Lizarda (ukłony) biblioteki getpar.mae, która obsługuje linię komend Sparty i DOS-a II+/D, a innych pewnie nie ...

KMK
? HEX$(6670358)

5

Pierwsza sprawa: relokacja. Mysle, ze pomysl z wyrownaniem do granicy strony to raczej obejscie, a nie rozwiazanie problemu jakim mamy z mnogoscia trybow adresowania.

Można oczywiście dawać oddzielne fixupy na młodszy i starszy bajt, ale w takim układzie blok fixupów robi się dwakroć dłuższy. Nie wiem, czy gra jest warta świeczki. Traci się w ten sposób do 255 bajtów pamięci, ale zyskuje na długości pliku, czasie ładowania, wielkości loadera (to jest zaniedbywalne dopiero kiedy loader mamy zintegrowany z systemem).

Dodatkowo nie doczytalem (przeoczylem?) jak relokator odroznia argument 2-bajtowy (np. wewnetrzne jsr) od 1-bajtowego (np. wspomniane lda #<costam).

Po fladze APAGE. Kiedy jest wyzerowana, wszystkie adresy muszą mieć postać ciągłą (lo-hi jedno za drugim).

Moje spostrzezenia sa zreszta oparte na tym artykule. Jest tam zawartych kilka (nie wszystkie) ciekawych spostrzezen.

Owszem, ciekawy artykuł. Jednak nie jestem pewien, czy ten format nie jest "za dokładnie" przemyślany. Po co na przykład adresy oryginalnej kompilacji segmentu TEXT i DATA w nagłówku? Albo flaga rodzaju CPU - czy DOS ma odmawiać ładowania pliku z flagą 65c816 jeśli mamy 6502? A co z programami, które chodzą na obydwu?

Część rzeczy z artykułu mój format implementuje, są to: info o autorze (patrz opcjonalny tekst w nagłówku), możliwość rozszerzenia formatu na większą długość słowa (tam 32 bity, u mnie 24 - mogę zmienić, jeśli to ma sens), "split addresses" i to chyba dokładnie tak samo jak u mnie (wyrównanie do strony), możliwość pełnej relokacji (co do bajtu).

Co do segmentów, pisząc o tym miałem na myśli segmenty kodu takie, jakie są w pliku $FFFF. Jeśli idzie o podział na segmenty TEXT/DATA/BSS (jak w ST np.), oraz proponowane w artykule STACK, ZERO i REF, to czemu nie, mogę zaimplementować. Tylko z takim nagłówkiem dość trudno będzie wypuścić w tym formacie demo 256 bajtów  :lol:

Myślę, że zaletą pierwszorzędną - na razie - będzie to, że pliki relokowalne będzie można tworzyć nie rezygnując ze swojego ulubionego asemblera. Jak mówię, stworzyłem program (działający z linii komend) który przetwarza pliki binarne np. MAE na nowy format. Na razie bardzo beta, ale się rozwija ;)

KMK
? HEX$(6670358)

6

Mam wątpliwość, czy ma sens wymyślanie od nowa formatu pliku relokowalnego, gdy od dawna funkcjonuje format relokowalny SpartaDos X z fixupami.
Czemu nie chciałeś bazować na tamtym i np. uzupełnić go o obsługę 65816 :?: Przynajmniej miałbyś gotową część kodu.

7

Bo format Sparty X, o ile mi wiadomo, ma ograniczenie odnośnie dzielonych adresów, na przykład. Poza tym jakaż to "część kodu" jest gotowa w tym przypadku?

KMK
? HEX$(6670358)

8

Chodzi o to, że pisząc nowy loader można wykorzystać kod Sparty dla bloków $FFFA-FE i dopisać tylko obsługę nowych rzeczy.
Pod SDX możnaby nawet napisać nowy loader np. Y.COM, który wołałby funkcje Sparty a obsługiwał tylko rozszerzenia, np. obsługę dzielonych adresów.
Sparta ma też fajną funkcję umieszczania bloku w bankach pamięci rozszerzonej - to by się też przydało w nowym formacie (dla zwykłego 6502).
Wydaje mi się też, że format fixupów w Sparcie jest bardziej kompaktowy niż Twoja propozycja. Są tam ofsety względem ostatniej poprawki, co daje zwykle 1 bajt.
Nie zauważyłem też nigdzie adresu bazowego programu, czyli tego którego używa programista. Czy to znaczy że zawsze asembluje się od $0000?

9

Można i tak. Nie pamiętam w tej chwili detali formatu relokowalnego SDX, no ale on i tak nie ma tego, co chciałby Laoo: segmentów TEXT/DATA/BSS itd.

Na ładowanie do banków pamięci i tym podobne bajery zarezerwowałem flagi w nagłówku, ale na razie chcę sobie poradzić z normalną pamięcią.

O napisaniu nie Y.COM, ale wręcz nowego X.COM też myślałem i zamierzam to zrobić. Ale na razie dopracowuję program konwertujący binaria. Oczywiście nie widzę większego problemu, żeby był on w stanie wyprodukować również binaria Sparty X: pliki różnią się formatem, ale nie co do zasady.

W ten sposób można byłoby w końcu w miarę wygodnie je pisać, bez konieczności używania FA (salva reverentia auctoris, wolę MAE).

Format fixupów u mnie kompaktowy nie jest, ale za to jest najprostszy możliwy (z punktu widzenia loadera). Ale żeby się do tego nie ograniczać, dodałem na początku bloku fixupów kod ich formatu. W ten sposób - teoretycznie - program będzie mógł mieć taki format fixupów, jaki będzie wygodny.

Adres ładowania programu jest określany przez loader. Program kompilujesz pod adres jaki chcesz, a potem - z zachowaniem pewnej dość nieskomplikowanej procedury - przepuszczasz przez mkrel.com i już.

KMK
? HEX$(6670358)

10

Można i tak. Nie pamiętam w tej chwili detali formatu relokowalnego SDX, no ale on i tak nie ma tego, co chciałby Laoo: segmentów TEXT/DATA/BSS itd.

BSS akurat jest. W Fast Assemblerze tworzysz go poprzez:

BLK EMPTY długość rodzaj_pamięci
Zawsze mam rację, tylko nikt mnie nie słucha.

11

Lizard, kurde felek, znowy masz rację?! Jesteś gorszy ode mnie! (Tkacz potwierdzi).

12

Ale osso chozzi?

Zawsze mam rację, tylko nikt mnie nie słucha.

13

A o to, że Tkacz się zawsze skarżył, że we wszystkich dyskusjach to ja mam rację. Tylko, bałwan jeden, nigdy mnie nie słucha.

(Tak naprawdę, na manie racji jest bardzo prosty algorytm, ale go nie zdradzę.)

14

A tak, pamiętam jak kiedyś Tkacz skarżył sie o to. Twój algorytm nie jest mi potrzebny, bo jak widzisz mam własny i skuteczniejszy od Twojego. ;)

Zawsze mam rację, tylko nikt mnie nie słucha.

15

Nie wiem, czy lepszy, bo jeszcze nie było chyba kolizji między Twoim a moim algorytmem. I - jeśli są opracowane na podobnym założeniu - nie będzie.

16

BSS akurat jest. W Fast Assemblerze tworzysz go poprzez:

BLK EMPTY długość rodzaj_pamięci

O rozmiarze do 16 MB?

KMK
? HEX$(6670358)

17

Nie, w  tej chwili oczywiście max. 64kB, ale przecież można to rozbudować, dodając jeden bit (w tej chwili nieużywany przez Spartę) i podawać większe rozmiary. A swoją drogą na co zamierzasz przeznaczyć te zaalokowane megabajty? 8)

Według mnie segmenty opisane w artykule są trochę na wyrost. Dopóki ktoś nie napisze systemu wielozadaniowego do Atarki to będą używane niezgodnie z przeznaczeniem.
Bo np. segment TEXT ma mieścić kod niemodyfikowany. Tymczasem przecież często wykorzystuje się samomodyfikowację w programach. To oznacza że taki kod trzeba byłoby umieszczać w segmencie DATA ??
Bardziej jednak podoba mi się podejście jakie jest w Sparcie: łączenie kodu relokowalnego i zwykłego, rezerwacja pamięci dają duże możliwości.

Trzeba też pamiętać, że często istnieje konieczność aktualizacji adresów znajdujących się poza kodem relokowalnym. Np. przy definiowaniu nowego urządzenia w tablicy handlerów OSa lub w innych stałych miejscach trzeba umieścić adresy PO relokacji kodu. Sparta załatwia bez problemu tę sprawę.

18

Podział programu na segmenty TEXT i DATA jest dla mnie raczej umowny. Nikt i nic nie może mi zabronić umieszczeniu danych w segmencie kodu ani kodu w segmencie danych (i odwoływać się do niego przez zwykłe JSR lub JMP). Segmenty są raczej pomocne dla asemblera, który mając kilka deklaracji TEXT czy DATA może je scalać w pojedynczy ciągły blok. Przykład:

    .text
    lda vfname
    ldx vfname+1
    jsr fopen

    .data
vfname .rw fname         ; relocatable word ;)
fname  .by "D:nazwa.ext"

    .text
fopen sta $0314
    stx $0315
    ...

Aembler powyższy przykład powinien obrobić tak, żeby dwa segmenty TEXT następowały po sobie a na końcu DATA.

Co innego BSS. Tu jak powszechnie wiadomo (albo i nie) chodzi o zarezerwowanie pamięci, ale nie zmienianie jej, ani nie ładowanie doń czegokolwiek.

Zawsze mam rację, tylko nikt mnie nie słucha.

19

A swoją drogą na co zamierzasz przeznaczyć te zaalokowane megabajty? 8)

A ty, jak instalujesz sobie w Atari rozszerzenie RAM-u, to odpowiadasz najpierw na pytania, na co zamierzasz tę pamięć wykorzystać? Co za pytanie w ogóle.

Według mnie segmenty opisane w artykule są trochę na wyrost. Dopóki ktoś nie napisze systemu wielozadaniowego do Atarki to będą używane niezgodnie z przeznaczeniem.
Bo np. segment TEXT ma mieścić kod niemodyfikowany. Tymczasem przecież często wykorzystuje się samomodyfikowację w programach. To oznacza że taki kod trzeba byłoby umieszczać w segmencie DATA ??

No nie, rozumiesz to chyba zbyt dosłownie. Segment TEXT jest przeznaczony na kod (modyfikowany czy nie), segment DATA na dane preinicjowane, a segment BSS na dane nie preinicjowane. Ale jeśli masz życzenie, możesz dane umieszczać w segmencie TEXT, a kod w segmencie DATA (jedynie w segmencie BSS nie możesz niczego umieszczać oprócz pustego miejsca). Tak więc, jeśli chcesz mieć jeden segment na wszystko (segment TEXT) - to proszę bardzo, nie ma przeciwwskazań. Jednak chodzi o to, żeby, kiedy się to wyda potrzebne, mieć możność podziału programu na te części.

Bardziej jednak podoba mi się podejście jakie jest w Sparcie: łączenie kodu relokowalnego i zwykłego, rezerwacja pamięci dają duże możliwości.

Przecież nikt ci nie zabrania korzystania z binariów Sparty X :)

Trzeba też pamiętać, że często istnieje konieczność aktualizacji adresów znajdujących się poza kodem relokowalnym. Np. przy definiowaniu nowego urządzenia w tablicy handlerów OSa lub w innych stałych miejscach trzeba umieścić adresy PO relokacji kodu. Sparta załatwia bez problemu tę sprawę.

Słucham? A gdzie tu problem? Przecież PO relokacji adresy są ustalone. Relokacja jest transparentna dla programu, on nic o niej nie wie. A poza tym relokacji podlegają jedynie adresy wewnętrzne programu (bo tylko to ma sens). Mógłbyś mi przybliżyć, gdzie tu widzisz problem?

KMK
? HEX$(6670358)

20

Ale jeśli masz życzenie, możesz dane umieszczać w segmencie TEXT, a kod w segmencie DATA (jedynie w segmencie BSS nie możesz niczego umieszczać oprócz pustego miejsca). Tak więc, jeśli chcesz mieć jeden segment na wszystko (segment TEXT) - to proszę bardzo, nie ma przeciwwskazań. Jednak chodzi o to, żeby, kiedy się to wyda potrzebne, mieć możność podziału programu na te części.

O tymwłaśnie pisałem. Wiem po co wymyślono rozdział na kod, dane pre i dane niepre. ;)

Ale dobrze by było, by segmenty mogły być ładowane w różne miejsca pamięci, nie jeden po drugim. Takie podejście choć częściowo zapobiegałoby fragmentacji pamięci (zwłaszcza, gdybyś dorobili sie jakiejś OSy wielozadaniowej).

Zawsze mam rację, tylko nikt mnie nie słucha.

21

Przecież jak segmenty będą ładowane jeden po drugim, to tym samym będą ładowane w różne miejsca pamięci, nie wiem o co panu chozi :D

Jak proponujesz te "różne miejsca" zdefiniować?

KMK
? HEX$(6670358)

22

Taka sytuację:
Mamy rezydenta działającego na przerwaniach, który alokuje sobie w pewnym momencie trochę pamięci. My w tym czasie ładujemy program, ale rezydent zwalnia w tym czasie przydzielony obszar powiedzmy w momencie obróbki bloku TEXT (relokacja, aktualizacja adresów, itp.) System przystępuje teraz do ładowania bloku DATA, który jest na tyle mały by mógł zostać załadowany w to miejsce, które przed chwilą zwolnił TSR. Jeśli blok DATA zostanie załadowany właśnie w to miejsce, to układ będzie taki: ˇ TSR
ˇ DATA naszego programu
ˇ ewentualnie nie wykorzystana pamięć (resztaka po malloc by TSR)
ˇ TEXT naszego programu
Jeśli natomiast system załaduje DATA bezpośrednio za TEXT, to otrzymamy: ˇ TSR
ˇ dziura po malloc by TSR
ˇ TEXT naszego programu
ˇ DATA naszego programu
Jeśli w programie wystąpi malloc, to może okazać się, że zabraknie na jego wykonanie kilku bajtów, które mogłyby zostać przydzielone, gdyby DATA siedział w obszarze zwolnionym przez TSR-a.

Zawsze mam rację, tylko nikt mnie nie słucha.

23

Nie widzę, jak z procedury przerwania można byłoby alokować pamięć bez ryzyka powalenia się wszystkiego - a co jeśli przerwanie wystąpi w środku wykonywania się - hipotetycznego jak dotąd - malloc()?

W systemie z multitaskingiem fragmentacja pamięci i tak będzie występować - bez dobrego MMU się tego nie uniknie. Natomiast w systemie bez multitaskingu mamy do czynienia z jednym programem aplikacyjnym, który po wyjściu z siebie pamięć zwalnia - a więc fragmentacja nie grozi.

Co do TSR-ów, to chyba nie ma aż tak wiele programów TSR, które z poziomu przerwania wołałyby funkcje systemu, CIO dajmy na to.

KMK
? HEX$(6670358)

24

Nie widzę, jak z procedury przerwania można byłoby alokować pamięć bez ryzyka powalenia się wszystkiego - a co jeśli przerwanie wystąpi w środku wykonywania się - hipotetycznego jak dotąd - malloc()?

W systemie z multitaskingiem fragmentacja pamięci i tak będzie występować - bez dobrego MMU się tego nie uniknie. Natomiast w systemie bez multitaskingu mamy do czynienia z jednym programem aplikacyjnym, który po wyjściu z siebie pamięć zwalnia - a więc fragmentacja nie grozi.

Co do TSR-ów, to chyba nie ma aż tak wiele programów TSR, które z poziomu przerwania wołałyby funkcje systemu, CIO dajmy na to.

E tam. Czepiasz sie, to był tylko przykład, pierwszy z brzegu pomysł jaki mi przyszedł do głowy. Nie dyskutujemy tu o mallocach na poziomie przerwań, tylko o segmentach programu. Zauważ, że gdy dawno temu narzekałem, że w ST bloki ładują się jetden po drugim zamiast w najbardziej pasujące miejsce, przyznałeś mi rację. To był efekt tego, że twórcom TOS-a nie przyszło do głowy, że na Atari ST może pojawić sie multitasking. Ja dmucham na zimne, stąd moje wywody.

Zawsze mam rację, tylko nikt mnie nie słucha.

25

No tak, rozmieszczenie segmentów jeden za drugim może świadczyc o krótkowzroczności twórców systemu, ale z innego punktu widzenia może świadczyć o dalekowzroczności: w końcu jeśli masz wirtuala i brak fragmentacji, to jest to dokładnie wszystko jedno, gdzie są segmenty. A skoro jest wszystko jedno, to najprościej je umieścić po kolei.

Oczywiście segmenty DATA i BSS można - o ile czegoś nie przeoczam - umieścić w dowolnym miejscu, definicja nagłówka tego nie wyklucza.

KMK
? HEX$(6670358)