{ This file is part of the Free Pascal run time library. Copyright (c) 2008 by Giulio Bernardi Resource writer for ELF files See the file COPYING.FPC, included in this distribution, for details about the copyright. 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. **********************************************************************} type (* generic TElfRelocTable<_TPElfRela_,_TElfRela_,_TPElfRel_,_TElfRel_,_Tword_> = class ... TElf32RelocTable = specialize TElfRelocTable; TElf64RelocTable = specialize TElfRelocTable; *) _TElfRelocTable_= class private fList : TFPList; fRelocType : byte; fEntrySize : integer; fSectionType : integer; fSectionName : string; function GetCount : integer; function GetItem(index : integer) : _TPElfRela_; protected public constructor Create(const fRelocInfo : TElfRelocInfo); destructor Destroy; override; procedure Add(const aOffset,aValue : _Tword_; aSymIdx : longword); procedure Clear; property Count : integer read GetCount; property Items[index : integer] : _TPElfRela_ read GetItem; default; property EntrySize : integer read fEntrySize; property SectionType : integer read fSectionType; property SectionName : string read fSectionName; end; { TElfSubWriter } (* generic TElfSubWriter<_TElfRelocTable_,_TElfHdr_,_TElfSectHdr_,_TElfSymbol_, _TPElfRela_,_TElfRela_,_TResHdr_,_TResInfoNode_> = class ... TElf32SubWriter = specialize TElfSubWriter; TElf64SubWriter = specialize TElfSubWriter; *) _TElfSubWriter_ = class(TAbstractElfSubWriter) private fRelocInfo : TElfRelocInfo; fRelocTable : _TElfRelocTable_; procedure WriteEmptyElfHeader(aStream : TStream); procedure WriteResHeader(aStream : TStream; aResources : TResources); procedure WriteNodeInfos(aStream : TStream); procedure WriteSectHeaders(aStream : TStream); procedure FixElfHeader(aStream : TStream); procedure WriteSymbols(aStream : TStream); procedure WriteRelocations(aStream : TStream); protected procedure PrescanResourceTree; override; procedure Write(aResources : TResources; aStream : TStream); override; procedure WriteNodeInfo(aStream : TStream; aNode : TResourceTreeNode); override; public constructor Create(aParent : TElfResourceWriter; const aMachineType : integer; const aOppositeEndianess : boolean); override; destructor Destroy; override; end; { TElfRelocTable } function _TElfRelocTable_.GetCount: integer; begin Result:=fList.Count; end; function _TElfRelocTable_.GetItem(index: integer): _TPElfRela_; begin Result:=_TPElfRela_(fList[index]); end; constructor _TElfRelocTable_.Create(const fRelocInfo : TElfRelocInfo); begin fList:=TFPList.Create; fRelocType:=fRelocInfo.RelocType; fSectionType:=fRelocInfo.SectionType; case fSectionType of SHT_REL : begin fEntrySize:= sizeof(_TElfRel_); fSectionName:='.rel'+RsrcSectName; end; SHT_RELA : begin fEntrySize:= sizeof(_TElfRela_); fSectionName:='.rela'+RsrcSectName; end; end; end; destructor _TElfRelocTable_.Destroy; begin Clear; fList.Free; end; procedure _TElfRelocTable_.Add(const aOffset,aValue : _Tword_; aSymIdx : longword); var p : _TPElfRela_; begin p:=GetMem(sizeof(_TElfRela_)); p^.Offset:=aOffset; P^.Info:=aSymIdx; {$IF _TElfRelocTable_=TElf64RelocTable} P^.Info:=P^.Info shl 32; P^.Info:=P^.Info or fRelocType; {$ELSE} P^.Info:=P^.Info shl 8; P^.Info:=P^.Info or (fRelocType and $FF); {$ENDIF} p^.addend:=aValue; fList.Add(p); end; procedure _TElfRelocTable_.Clear; var i : integer; p : _TPElfRela_; begin for i:=0 to fList.Count-1 do begin p:=_TPElfRela_(fList[i]); FreeMem(p); end; fList.Clear; end; { TElfSubWriter } procedure _TElfSubWriter_.PrescanResourceTree; begin fResStringTable.Clear; fRoot.SubDirRVA:=sizeof(_TResHdr_)+sizeof(_TResInfoNode_); fResStringTable.StartOfs:=PrescanNode(fRoot,sizeof(_TResInfoNode_)); if fResStringTable.Used then fDataCurOfs:=NextAligned(fDataAlignment,fResStringTable.StartOfs+fResStringTable.Size) else fDataCurOfs:=fResStringTable.StartOfs; end; procedure _TElfSubWriter_.WriteEmptyElfHeader(aStream: TStream); var hdr : _TElfHdr_; begin FillByte(hdr,sizeof(hdr),0); aStream.WriteBuffer(hdr,sizeof(hdr)); end; procedure _TElfSubWriter_.WriteResHeader(aStream: TStream; aResources: TResources); var hdr : _TResHdr_; begin hdr.count:=aResources.Count; hdr.usedhandles:=0; hdr.handles:=0; fSymbolTable.AddSection(RSRCSECT_IDX); fSymbolTable.AddSection(HANDLESECT_IDX); case fRelocInfo.SectionType of SHT_REL : hdr.rootptr:=sizeof(hdr); SHT_RELA : hdr.rootptr:=0; end; fRelocTable.Add(0,sizeof(hdr),RSRCSECT_IDX); fRelocTable.Add(sizeof(hdr.rootptr)+sizeof(hdr.count)+sizeof(hdr.usedhandles),0,HANDLESECT_IDX); if fOppositeEndianess then begin hdr.rootptr:=SwapEndian(hdr.rootptr); hdr.count:=SwapEndian(hdr.count); //handles must be fixed later // hdr.usedhandles:=SwapEndian(hdr.usedhandles); // hdr.handles:=SwapEndian(hdr.handles); end; aStream.WriteBuffer(hdr,sizeof(hdr)); end; procedure _TElfSubWriter_.WriteNodeInfos(aStream: TStream); begin fCurOfs:=sizeof(_TResHdr_); WriteNodeInfo(aStream,fRoot); WriteSubNodes(aStream,fRoot); end; procedure _TElfSubWriter_.WriteNodeInfo(aStream: TStream; aNode: TResourceTreeNode); var infonode : _TResInfoNode_; begin if aNode.Desc.DescType=dtID then infonode.nameid:=aNode.Desc.ID else begin infonode.nameid:=fResStringTable.StartOfs+aNode.NameRVA; fRelocTable.Add(fCurOfs,infonode.nameid,RSRCSECT_IDX); if fRelocInfo.SectionType=SHT_RELA then infonode.nameid:=0; end; infonode.ncount:=aNode.NamedCount; if aNode.IsLeaf then begin infonode.idcountsize:=aNode.Data.RawData.Size; infonode.subptr:=fDataCurOfs; fDataCurOfs:=NextAligned(fDataAlignment,fDataCurOfs+infonode.idcountsize); end else begin infonode.idcountsize:=aNode.IDCount; infonode.subptr:=aNode.SubDirRVA; end; fRelocTable.Add( fCurOfs+sizeof(infonode.nameid)+sizeof(infonode.ncount)+ sizeof(infonode.idcountsize),infonode.subptr,RSRCSECT_IDX); if fRelocInfo.SectionType=SHT_RELA then infonode.subptr:=0; if fOppositeEndianess then begin infonode.nameid:=SwapEndian(infonode.nameid); infonode.ncount:=SwapEndian(infonode.ncount); infonode.idcountsize:=SwapEndian(infonode.idcountsize); infonode.subptr:=SwapEndian(infonode.subptr); end; aStream.WriteBuffer(infonode,sizeof(infonode)); inc(fCurOfs,sizeof(infonode)); end; procedure _TElfSubWriter_.WriteSectHeaders(aStream: TStream); var i : integer; orig : PElf64SectHdr; hdr : _TElfSectHdr_; begin Align(fDataAlignment,aStream); fSectHdrOffset:=aStream.Position; for i:=0 to fSections.Count-1 do begin orig:=fSections[i]; {$IF _TElfSubWriter_=TElf64SubWriter} hdr:=orig^; {$ELSE} hdr.NameIdx:=orig^.NameIdx; hdr._Type:=orig^._Type; hdr.Flags:=orig^.Flags; hdr.Address:=orig^.Address; hdr.Offset:=orig^.Offset; hdr.Size:=orig^.Size; hdr.Link:=orig^.Link; hdr.Info:=orig^.Info; hdr.AddrAlign:=orig^.AddrAlign; hdr.EntSize:=orig^.EntSize; {$ENDIF} if fOppositeEndianess then begin hdr.NameIdx:=SwapEndian(hdr.NameIdx); hdr._Type:=SwapEndian(hdr._Type); hdr.Flags:=SwapEndian(hdr.Flags); hdr.Address:=SwapEndian(hdr.Address); hdr.Offset:=SwapEndian(hdr.Offset); hdr.Size:=SwapEndian(hdr.Size); hdr.Link:=SwapEndian(hdr.Link); hdr.Info:=SwapEndian(hdr.Info); hdr.AddrAlign:=SwapEndian(hdr.AddrAlign); hdr.EntSize:=SwapEndian(hdr.EntSize); end; aStream.WriteBuffer(hdr,sizeof(hdr)); end; end; procedure _TElfSubWriter_.FixElfHeader(aStream: TStream); var hdr : _TElfHdr_; begin hdr._Type:=ET_REL; hdr.Machine:=fMachineType; hdr.Version:=EV_CURRENT; hdr.Entry:=0; hdr.ProgHdrOffset:=0; hdr.SectHdrOffset:=fSectHdrOffset; hdr.Flags:=fMachineFlags; hdr.HdrSize:=sizeof(_TElfHdr_)+sizeof(TElfIdent); hdr.ProgHdrEntrySize:=0; hdr.ProgHdrNum:=0; hdr.SectHdrEntrySize:=sizeof(_TElfSectHdr_); hdr.SectHdrNum:=fSections.Count; hdr.NameTableIndex:=fShStrTabIdx; if fOppositeEndianess then begin hdr._Type:=SwapEndian(hdr._Type); hdr.Machine:=SwapEndian(hdr.Machine); hdr.Version:=SwapEndian(hdr.Version); hdr.Entry:=SwapEndian(hdr.Entry); hdr.ProgHdrOffset:=SwapEndian(hdr.ProgHdrOffset); hdr.SectHdrOffset:=SwapEndian(hdr.SectHdrOffset); hdr.Flags:=SwapEndian(hdr.Flags); hdr.HdrSize:=SwapEndian(hdr.HdrSize); hdr.ProgHdrEntrySize:=SwapEndian(hdr.ProgHdrEntrySize); hdr.ProgHdrNum:=SwapEndian(hdr.ProgHdrNum); hdr.SectHdrEntrySize:=SwapEndian(hdr.SectHdrEntrySize); hdr.SectHdrNum:=SwapEndian(hdr.SectHdrNum); hdr.NameTableIndex:=SwapEndian(hdr.NameTableIndex); end; aStream.Position:=sizeof(TElfIdent); aStream.WriteBuffer(hdr,sizeof(hdr)); end; procedure _TElfSubWriter_.WriteSymbols(aStream: TStream); var i : integer; orig : PElf64Symbol; sym : _TElfSymbol_; startpos : int64; begin Align(fDataAlignment,aStream); startpos:=aStream.Position; for i:=0 to fSymbolTable.Count-1 do begin orig:=fSymbolTable[i]; {$IF _TElfSubWriter_=TElf64SubWriter} sym:=orig^; {$ELSE} sym.Name:=orig^.Name; sym.Value:=orig^.Value; sym.Size:=orig^.Size; sym.Info:=orig^.Info; sym.Other:=orig^.Other; sym.SectIdx:=orig^.SectIdx; {$ENDIF} if fOppositeEndianess then begin sym.Name:=SwapEndian(sym.Name); sym.Value:=SwapEndian(sym.Value); sym.Size:=SwapEndian(sym.Size); sym.SectIdx:=SwapEndian(sym.SectIdx); end; aStream.WriteBuffer(sym,sizeof(sym)); end; fSymTabIdx:=fSections.Add('.symtab',SHT_SYMTAB,0,startpos, fSymbolTable.Count*sizeof(_TElfSymbol_),sizeof(_TElfSymbol_),fSymStrTabIdx, fSymbolTable.FirstGlobal,fDataAlignment); end; procedure _TElfSubWriter_.WriteRelocations(aStream: TStream); var orig : _TPElfRela_; rel : _TElfRela_; startpos : int64; i : integer; begin Align(fDataAlignment,aStream); startpos:=aStream.Position; for i:=0 to fRelocTable.Count-1 do begin orig:=fRelocTable[i]; rel:=orig^; if fOppositeEndianess then begin rel.Offset:=SwapEndian(rel.Offset); rel.Info:=SwapEndian(rel.Info); rel.Addend:=SwapEndian(rel.Addend); end; aStream.WriteBuffer(rel,fRelocTable.EntrySize); end; fSections.Add(fRelocTable.SectionName,fRelocTable.SectionType,0,startpos, fRelocTable.Count*fRelocTable.EntrySize,fRelocTable.EntrySize, fSymTabIdx,1,fDataAlignment); end; procedure _TElfSubWriter_.Write(aResources: TResources; aStream: TStream); begin fRoot:=TRootResTreeNode(fParent.GetTree(aResources)); WriteEmptyElfHeader(aStream); fSectionStart:=aStream.Position; PrescanResourceTree; WriteResHeader(aStream,aResources); WriteNodeInfos(aStream); WriteResStringTable(aStream); WriteRawData(aStream); fSections.Add(RsrcSectName, SHT_PROGBITS,SHF_ALLOC or SHF_WRITE,fSectionStart, fDataCurOfs,fDataAlignment); AddEmptySections(aResources,aStream); fSymbolTable.AddGlobal('FPC_RESSYMBOL',0,0,STT_OBJECT,RSRCSECT_IDX); WriteStrTab(aStream); WriteSymbols(aStream); WriteRelocations(aStream); WriteShStrTab(aStream); WriteSectHeaders(aStream); FixElfHeader(aStream); end; constructor _TElfSubWriter_.Create(aParent : TElfResourceWriter; const aMachineType: integer; const aOppositeEndianess: boolean); begin inherited Create(aParent, aMachineType, aOppositeEndianess); with fRelocInfo do case aMachineType of EM_386 : begin RelocType:=R_386_32; SectionType:=SHT_REL; end; EM_PPC : begin RelocType:=R_PPC_ADDR32; SectionType:=SHT_RELA; end; EM_ARM : begin RelocType:=R_ARM_ABS32; SectionType:=SHT_REL; end; EM_68K : begin RelocType:=R_68K_32; SectionType:=SHT_RELA; end; EM_SPARC : begin RelocType:=R_SPARC_32; SectionType:=SHT_RELA; end; EM_X86_64 : begin RelocType:=R_x86_64_64; SectionType:=SHT_RELA; end; EM_PPC64 : begin RelocType:=R_PPC64_ADDR64; SectionType:=SHT_RELA; end; EM_ALPHA : begin RelocType:=R_ALPHA_REFQUAD; SectionType:=SHT_RELA; end; EM_IA_64 : begin RelocType:=R_IA64_DIR64LSB; SectionType:=SHT_RELA; end; else raise EElfResourceWriterUnknownMachineException.Create(''); end; fRelocTable:=_TElfRelocTable_.Create(fRelocInfo); {$IF _TElfSubWriter_=TElf64SubWriter} fDataAlignment:=8; {$ELSE} fDataAlignment:=4; {$ENDIF} if aMachineType=EM_IA_64 then fMachineFlags:=EF_IA_64_ABI64 else fMachineFlags:=0; end; destructor _TElfSubWriter_.Destroy; begin fRelocTable.Free; inherited Destroy; end;