123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- {
- 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<PElf32Rela,TElf32Rela,
- PElf32Rel,TElf32Rel,longword>;
- TElf64RelocTable = specialize TElfRelocTable<PElf64Rela,TElf64Rela,
- PElf64Rel,TElf64Rel,qword>;
- *)
- _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<TElf32RelocTable,_TElf32Hdr_,
- TElf32SectHdr,TElf32Symbol,PElf32Rela,TElf32Rela,TResHdr32,TResInfoNode32>;
- TElf64SubWriter = specialize TElfSubWriter<TElf64RelocTable,_TElf64Hdr_,
- TElf64SectHdr,TElf64Symbol,PElf64Rela,TElf64Rela,TResHdr64,TResInfoNode64>;
- *)
- _TElfSubWriter_ = class(TAbstractElfSubWriter)
- private
- fRelocInfo : TElfRelocInfo;
- fRelocTable : _TElfRelocTable_;
- procedure PrescanResourceTree; override;
- procedure WriteEmptyElfHeader(aStream : TStream);
- procedure WriteResHeader(aStream : TStream; aResources : TResources);
- procedure WriteNodeInfos(aStream : TStream);
- procedure WriteNodeInfo(aStream : TStream; aNode : TResourceTreeNode); override;
- procedure WriteSectHeaders(aStream : TStream);
- procedure FixElfHeader(aStream : TStream);
- procedure WriteSymbols(aStream : TStream);
- procedure WriteRelocations(aStream : TStream);
- protected
- procedure Write(aResources : TResources; aStream : TStream); 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;
|