123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639 |
- {
- $Id$
- Copyright (c) 1998-2002 by Peter Vreman
- Contains the base stuff for binary object file writers
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ****************************************************************************
- }
- unit ogbase;
- {$i fpcdefs.inc}
- interface
- uses
- {$ifdef Delphi}
- sysutils,
- dmisc,
- {$else Delphi}
- strings,
- dos,
- {$endif Delphi}
- { common }
- cclasses,
- { targets }
- systems,
- { outputwriters }
- owbase,owar,
- { assembler }
- cpubase,aasmbase,aasmtai;
- type
- tobjectoutput = class
- protected
- { writer }
- FWriter : tobjectwriter;
- function writedata(data:TAsmObjectData):boolean;virtual;abstract;
- public
- constructor create(smart:boolean);
- destructor destroy;override;
- function newobjectdata(const n:string):TAsmObjectData;virtual;
- function startobjectfile(const fn:string):boolean;
- function writeobjectfile(data:TAsmObjectData):boolean;
- procedure exportsymbol(p:tasmsymbol);
- property Writer:TObjectWriter read FWriter;
- end;
- tobjectinput = class
- protected
- { reader }
- FReader : tobjectreader;
- protected
- function str2sec(const s:string):TSection;
- function readobjectdata(data:TAsmObjectData):boolean;virtual;abstract;
- public
- constructor create;
- destructor destroy;override;
- function newobjectdata(const n:string):TAsmObjectData;virtual;
- function readobjectfile(const fn:string;data:TAsmObjectData):boolean;virtual;
- property Reader:TObjectReader read FReader;
- end;
- texesection = class
- public
- name : string[32];
- available : boolean;
- secsymidx,
- datasize,
- datapos,
- memsize,
- mempos : longint;
- flags : cardinal;
- DataList : TLinkedList;
- constructor create(const n:string);
- destructor destroy;override;
- end;
- texeoutput = class
- protected
- { writer }
- FWriter : tobjectwriter;
- procedure WriteZeros(l:longint);
- procedure MapObjectdata(var datapos:longint;var mempos:longint);
- function writedata:boolean;virtual;abstract;
- public
- { info for each section }
- sections : array[TSection] of texesection;
- { global symbols }
- externalsyms : tsinglelist;
- commonsyms : tsinglelist;
- globalsyms : tdictionary;
- { list of all data of the object files to link }
- objdatalist : tlinkedlist;
- constructor create;
- destructor destroy;override;
- function newobjectinput:tobjectinput;virtual;
- procedure GenerateExecutable(const fn:string);virtual;abstract;
- function writeexefile(const fn:string):boolean;
- function CalculateSymbols:boolean;
- procedure CalculateMemoryMap;virtual;abstract;
- procedure addobjdata(objdata:TAsmObjectData);
- procedure FixUpSymbols;
- procedure FixUpRelocations;
- procedure addglobalsym(const name:string;ofs:longint);
- property Writer:TObjectWriter read FWriter;
- end;
- var
- exeoutput : texeoutput;
- implementation
- uses
- cutils,globtype,globals,verbose,fmodule,ogmap;
- {****************************************************************************
- tobjectoutput
- ****************************************************************************}
- constructor tobjectoutput.create(smart:boolean);
- begin
- { init writer }
- if smart and
- not(cs_asm_leave in aktglobalswitches) then
- FWriter:=tarobjectwriter.create(current_module.staticlibfilename^)
- else
- FWriter:=tobjectwriter.create;
- end;
- destructor tobjectoutput.destroy;
- begin
- FWriter.free;
- end;
- function tobjectoutput.newobjectdata(const n:string):TAsmObjectData;
- begin
- result:=TAsmObjectData.create(n);
- end;
- function tobjectoutput.startobjectfile(const fn:string):boolean;
- begin
- result:=false;
- { start the writer already, so the .a generation can initialize
- the position of the current objectfile }
- if not FWriter.createfile(fn) then
- Comment(V_Fatal,'Can''t create object '+fn);
- result:=true;
- end;
- function tobjectoutput.writeobjectfile(data:TAsmObjectData):boolean;
- begin
- if errorcount=0 then
- result:=writedata(data)
- else
- result:=true;
- { close the writer }
- FWriter.closefile;
- end;
- procedure tobjectoutput.exportsymbol(p:tasmsymbol);
- begin
- { export globals and common symbols, this is needed
- for .a files }
- if p.currbind in [AB_GLOBAL,AB_COMMON] then
- FWriter.writesym(p.name);
- end;
- {****************************************************************************
- texesection
- ****************************************************************************}
- constructor texesection.create(const n:string);
- begin
- name:=n;
- mempos:=0;
- memsize:=0;
- datapos:=0;
- datasize:=0;
- secsymidx:=0;
- available:=false;
- flags:=0;
- datalist:=TLinkedList.Create;
- end;
- destructor texesection.destroy;
- begin
- end;
- {****************************************************************************
- texeoutput
- ****************************************************************************}
- constructor texeoutput.create;
- var
- sec : TSection;
- begin
- { init writer }
- FWriter:=tobjectwriter.create;
- { object files }
- objdatalist:=tlinkedlist.create;
- { symbols }
- globalsyms:=tdictionary.create;
- globalsyms.usehash;
- globalsyms.noclear:=true;
- externalsyms:=tsinglelist.create;
- commonsyms:=tsinglelist.create;
- { sections }
- for sec:=low(TSection) to high(TSection) do
- sections[sec]:=texesection.create(target_asm.secnames[sec]);
- end;
- destructor texeoutput.destroy;
- var
- sec : TSection;
- begin
- for sec:=low(TSection) to high(TSection) do
- sections[sec].free;
- globalsyms.free;
- externalsyms.free;
- commonsyms.free;
- objdatalist.free;
- FWriter.free;
- end;
- function texeoutput.newobjectinput:tobjectinput;
- begin
- result:=tobjectinput.create;
- end;
- function texeoutput.writeexefile(const fn:string):boolean;
- begin
- result:=false;
- if FWriter.createfile(fn) then
- begin
- { Only write the .o if there are no errors }
- if errorcount=0 then
- result:=writedata
- else
- result:=true;
- { close the writer }
- FWriter.closefile;
- end
- else
- Comment(V_Fatal,'Can''t create executable '+fn);
- end;
- procedure texeoutput.addobjdata(objdata:TAsmObjectData);
- var
- sec : TSection;
- begin
- objdatalist.concat(objdata);
- { check which sections are available }
- for sec:=low(TSection) to high(TSection) do
- begin
- if assigned(objdata.sects[sec]) then
- begin
- sections[sec].available:=true;
- sections[sec].flags:=objdata.sects[sec].flags;
- end;
- end;
- end;
- procedure texeoutput.MapObjectdata(var datapos:longint;var mempos:longint);
- var
- sec : TSection;
- s : TAsmSection;
- alignedpos : longint;
- objdata : TAsmObjectData;
- begin
- { calculate offsets of each objdata }
- for sec:=low(TSection) to high(TSection) do
- begin
- if sections[sec].available then
- begin
- { set start position of section }
- sections[sec].datapos:=datapos;
- sections[sec].mempos:=mempos;
- { update objectfiles }
- objdata:=TAsmObjectData(objdatalist.first);
- while assigned(objdata) do
- begin
- s:=objdata.sects[sec];
- if assigned(s) then
- begin
- { align section }
- mempos:=align(mempos,$10);
- if assigned(s.data) then
- begin
- alignedpos:=align(datapos,$10);
- s.dataalignbytes:=alignedpos-datapos;
- datapos:=alignedpos;
- end;
- { set position and size of this objectfile }
- s.mempos:=mempos;
- s.datapos:=datapos;
- inc(mempos,s.datasize);
- if assigned(s.data) then
- inc(datapos,s.datasize);
- end;
- objdata:=TAsmObjectData(objdata.next);
- end;
- { calculate size of the section }
- sections[sec].datasize:=datapos-sections[sec].datapos;
- sections[sec].memsize:=mempos-sections[sec].mempos;
- end;
- end;
- end;
- procedure texeoutput.WriteZeros(l:longint);
- var
- empty : array[0..63] of char;
- begin
- if l>0 then
- begin
- fillchar(empty,l,0);
- FWriter.Write(empty,l);
- end;
- end;
- procedure texeoutput.FixUpSymbols;
- var
- sec : TSection;
- objdata : TAsmObjectData;
- sym,
- hsym : tasmsymbol;
- begin
- {
- Fixing up symbols is done in the following steps:
- 1. Update addresses
- 2. Update common references
- 3. Update external references
- }
- { Step 1, Update addresses }
- if assigned(exemap) then
- exemap.AddMemoryMapHeader;
- for sec:=low(TSection) to high(TSection) do
- if sections[sec].available then
- begin
- if assigned(exemap) then
- exemap.AddMemoryMapSection(sections[sec]);
- objdata:=TAsmObjectData(objdatalist.first);
- while assigned(objdata) do
- begin
- if assigned(objdata.sects[sec]) then
- begin
- if assigned(exemap) then
- exemap.AddMemoryMapObjectData(objdata,sec);
- hsym:=tasmsymbol(objdata.symbols.first);
- while assigned(hsym) do
- begin
- { process only the symbols that are defined in this section
- and are located in this module }
- if ((hsym.section=sec) or
- ((sec=sec_bss) and (hsym.section=sec_common))) then
- begin
- if hsym.currbind=AB_EXTERNAL then
- internalerror(200206303);
- inc(hsym.address,TAsmObjectData(hsym.objectdata).sects[sec].mempos);
- if assigned(exemap) then
- exemap.AddMemoryMapSymbol(hsym);
- end;
- hsym:=tasmsymbol(hsym.indexnext);
- end;
- end;
- objdata:=TAsmObjectData(objdata.next);
- end;
- end;
- { Step 2, Update commons }
- sym:=tasmsymbol(commonsyms.first);
- while assigned(sym) do
- begin
- if sym.currbind=AB_COMMON then
- begin
- { update this symbol }
- sym.currbind:=sym.altsymbol.currbind;
- sym.address:=sym.altsymbol.address;
- sym.size:=sym.altsymbol.size;
- sym.section:=sym.altsymbol.section;
- sym.typ:=sym.altsymbol.typ;
- sym.objectdata:=sym.altsymbol.objectdata;
- end;
- sym:=tasmsymbol(sym.listnext);
- end;
- { Step 3, Update externals }
- sym:=tasmsymbol(externalsyms.first);
- while assigned(sym) do
- begin
- if sym.currbind=AB_EXTERNAL then
- begin
- { update this symbol }
- sym.currbind:=sym.altsymbol.currbind;
- sym.address:=sym.altsymbol.address;
- sym.size:=sym.altsymbol.size;
- sym.section:=sym.altsymbol.section;
- sym.typ:=sym.altsymbol.typ;
- sym.objectdata:=sym.altsymbol.objectdata;
- end;
- sym:=tasmsymbol(sym.listnext);
- end;
- end;
- procedure texeoutput.FixUpRelocations;
- var
- objdata : TAsmObjectData;
- begin
- objdata:=TAsmObjectData(objdatalist.first);
- while assigned(objdata) do
- begin
- objdata.fixuprelocs;
- objdata:=TAsmObjectData(objdata.next);
- end;
- end;
- procedure texeoutput.addglobalsym(const name:string;ofs:longint);
- var
- sym : tasmsymbol;
- begin
- sym:=tasmsymbol(globalsyms.search(name));
- if not assigned(sym) then
- begin
- sym:=tasmsymbol.create(name,AB_GLOBAL,AT_FUNCTION);
- globalsyms.insert(sym);
- end;
- sym.currbind:=AB_GLOBAL;
- sym.address:=ofs;
- end;
- function TExeOutput.CalculateSymbols:boolean;
- var
- commonobjdata,
- objdata : TAsmObjectData;
- s : TAsmSection;
- sym,p : tasmsymbol;
- begin
- commonobjdata:=nil;
- CalculateSymbols:=true;
- {
- The symbol calculation is done in 3 steps:
- 1. register globals
- register externals
- register commons
- 2. try to find commons, if not found then
- add to the globals (so externals can be resolved)
- 3. try to find externals
- }
- { Step 1, Register symbols }
- objdata:=TAsmObjectData(objdatalist.first);
- while assigned(objdata) do
- begin
- sym:=tasmsymbol(objdata.symbols.first);
- while assigned(sym) do
- begin
- if not assigned(sym.objectdata) then
- internalerror(200206302);
- case sym.currbind of
- AB_GLOBAL :
- begin
- p:=tasmsymbol(globalsyms.search(sym.name));
- if not assigned(p) then
- globalsyms.insert(sym)
- else
- begin
- Comment(V_Error,'Multiple defined symbol '+sym.name);
- CalculateSymbols:=false;
- end;
- end;
- AB_EXTERNAL :
- externalsyms.insert(sym);
- AB_COMMON :
- commonsyms.insert(sym);
- end;
- sym:=tasmsymbol(sym.indexnext);
- end;
- objdata:=TAsmObjectData(objdata.next);
- end;
- { Step 2, Match common symbols or add to the globals }
- sym:=tasmsymbol(commonsyms.first);
- while assigned(sym) do
- begin
- if sym.currbind=AB_COMMON then
- begin
- p:=tasmsymbol(globalsyms.search(sym.name));
- if assigned(p) then
- begin
- if p.size<>sym.size then
- internalerror(200206301);
- end
- else
- begin
- { allocate new symbol in .bss and store it in the
- *COMMON* module }
- if not assigned(commonobjdata) then
- begin
- if assigned(exemap) then
- exemap.AddCommonSymbolsHeader;
- { create .bss section and add to list }
- s:=TAsmSection.create(target_asm.secnames[sec_common],0,true);
- commonobjdata:=TAsmObjectData.create('*COMMON*');
- commonobjdata.sects[sec_bss]:=s;
- addobjdata(commonobjdata);
- end;
- p:=TAsmSymbol.Create(sym.name,AB_GLOBAL,AT_FUNCTION);
- p.SetAddress(0,sec_common,s.datasize,sym.size);
- p.objectdata:=commonobjdata;
- commonobjdata.sects[sec_bss].alloc(sym.size);
- commonobjdata.symbols.insert(p);
- { update this symbol }
- if assigned(exemap) then
- exemap.AddCommonSymbol(p);
- { make this symbol available as a global }
- globalsyms.insert(p);
- end;
- sym.altsymbol:=p;
- end;
- sym:=tasmsymbol(sym.listnext);
- end;
- { Step 3 }
- sym:=tasmsymbol(externalsyms.first);
- while assigned(sym) do
- begin
- if sym.currbind=AB_EXTERNAL then
- begin
- p:=tasmsymbol(globalsyms.search(sym.name));
- if assigned(p) then
- begin
- sym.altsymbol:=p;
- end
- else
- begin
- Comment(V_Error,'Undefined symbol: '+sym.name);
- CalculateSymbols:=false;
- end;
- end;
- sym:=tasmsymbol(sym.listnext);
- end;
- end;
- {****************************************************************************
- tobjectinput
- ****************************************************************************}
- constructor tobjectinput.create;
- begin
- { init reader }
- FReader:=tobjectreader.create;
- end;
- destructor tobjectinput.destroy;
- begin
- FReader.free;
- end;
- function tobjectinput.newobjectdata(const n:string):TAsmObjectData;
- begin
- result:=TAsmObjectData.create(n);
- end;
- function tobjectinput.readobjectfile(const fn:string;data:TAsmObjectData):boolean;
- begin
- result:=false;
- { start the reader }
- if FReader.openfile(fn) then
- begin
- result:=readobjectdata(data);
- FReader.closefile;
- end;
- end;
- function tobjectinput.str2sec(const s:string):TSection;
- var
- t : TSection;
- begin
- for t:=low(TSection) to high(TSection) do
- begin
- if (s=target_asm.secnames[t]) then
- begin
- str2sec:=t;
- exit;
- end;
- end;
- str2sec:=sec_none;
- end;
- end.
- {
- $Log$
- Revision 1.13 2003-04-22 14:33:38 peter
- * removed some notes/hints
- Revision 1.12 2002/07/01 18:46:24 peter
- * internal linker
- * reorganized aasm layer
- Revision 1.11 2002/05/18 13:34:10 peter
- * readded missing revisions
- Revision 1.9 2002/05/14 19:34:43 peter
- * removed old logs and updated copyright year
- }
|