diff options
Diffstat (limited to 'compiler/ogbase.pas')
-rw-r--r-- | compiler/ogbase.pas | 572 |
1 files changed, 572 insertions, 0 deletions
diff --git a/compiler/ogbase.pas b/compiler/ogbase.pas new file mode 100644 index 0000000000..d9d7de488e --- /dev/null +++ b/compiler/ogbase.pas @@ -0,0 +1,572 @@ +{ + 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 + { common } + cclasses, + { targets } + systems, + { outputwriters } + owbase,owar, + { assembler } + 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 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(tnamedindexitem) + public + available : boolean; + secsymidx, + datasize, + datapos, + memsize, + mempos : longint; + flags : cardinal; + secdatalist : TLinkedList; + constructor create(const n:string); + destructor destroy;override; + end; + + texeoutput = class + private + procedure Sections_FixUpSymbol(s:tnamedindexitem;arg:pointer); + protected + { writer } + FWriter : tobjectwriter; + procedure MapObjectdata(var datapos:longint;var mempos:longint); + function writedata:boolean;virtual;abstract; + public + { info for each section } + sections : tdictionary; + { 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 + inherited createname(n); + mempos:=0; + memsize:=0; + datapos:=0; + datasize:=0; + secsymidx:=0; + available:=false; + flags:=0; + secdatalist:=TLinkedList.Create; + end; + + + destructor texesection.destroy; + begin + end; + + +{**************************************************************************** + texeoutput +****************************************************************************} + + constructor texeoutput.create; + 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:=tdictionary.create; + end; + + + destructor texeoutput.destroy; + begin + sections.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); + begin + objdatalist.concat(objdata); + end; + + + procedure texeoutput.MapObjectdata(var datapos:longint;var mempos:longint); +{$ifdef needrewrite} + 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; +{$endif needrewrite} + begin + end; + + + procedure texeoutput.Sections_FixUpSymbol(s:tnamedindexitem;arg:pointer); +{$ifdef needrewrite} + var + secdata : TAsmSection; + hsym : TAsmSymbol; + begin + with texesection(s) do + begin + if assigned(exemap) then + exemap.AddMemoryMapExeSection(TExeSection(s)); + secdata:=TAsmSection(secdatalist.first); + while assigned(secdata) do + begin + if assigned(exemap) then + exemap.AddMemoryMapObjectSection(secdata); + hsym:=tasmsymbol(secdata.owner.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=secdata) or + ((secdata.sectype=sec_bss) and (hsym.section.sectype=sec_common))) then + begin + if hsym.currbind=AB_EXTERNAL then + internalerror(200206303); + inc(hsym.address,secdata.mempos); + if assigned(exemap) then + exemap.AddMemoryMapSymbol(hsym); + end; + hsym:=tasmsymbol(hsym.indexnext); + end; + secdata:=TAsmSection(secdata.indexnext); + end; + end; + end; +{$endif needrewrite} + begin + end; + + + procedure texeoutput.FixUpSymbols; + var + sym : 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; + sections.foreach(@sections_fixupsymbol,nil); + { 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.owner:=sym.altsymbol.owner; + 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.owner:=sym.altsymbol.owner; + 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; + 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.owner) 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); + result:=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 } + commonobjdata:=TAsmObjectData.create('*COMMON*'); + commonobjdata.createsection(sec_bss,'',0,[aso_alloconly]); + addobjdata(commonobjdata); + end; + p:=TAsmSymbol.Create(sym.name,AB_GLOBAL,AT_FUNCTION); + commonobjdata.writesymbol(p); + 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; + + +end. |