1{
2    This file is part of the Free Pascal run time library.
3    Copyright (c) 2008 by Giulio Bernardi
4
5    Resource writer for ELF files
6
7    See the file COPYING.FPC, included in this distribution,
8    for details about the copyright.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
14 **********************************************************************}
15
16type
17
18(*
19  generic TElfRelocTable<_TPElfRela_,_TElfRela_,_TPElfRel_,_TElfRel_,_Tword_> = class
20  ...
21  TElf32RelocTable = specialize TElfRelocTable<PElf32Rela,TElf32Rela,
22                                               PElf32Rel,TElf32Rel,longword>;
23  TElf64RelocTable = specialize TElfRelocTable<PElf64Rela,TElf64Rela,
24                                               PElf64Rel,TElf64Rel,qword>;
25*)
26
27  _TElfRelocTable_= class
28  private
29    fList : TFPList;
30    fRelocType : longword;
31    fEntrySize : integer;
32    fSectionType : integer;
33    fSectionName : string;
34    function GetCount : integer;
35    function GetItem(index : integer) : _TPElfRela_;
36  protected
37  public
38    constructor Create(const fRelocInfo : TElfRelocInfo);
39    destructor Destroy; override;
40    procedure Add(const aOffset,aValue : _Tword_; aSymIdx : longword);
41    procedure Clear;
42    property Count : integer read GetCount;
43    property Items[index : integer] : _TPElfRela_ read GetItem; default;
44    property EntrySize : integer read fEntrySize;
45    property SectionType : integer read fSectionType;
46    property SectionName : string read fSectionName;
47  end;
48
49  { TElfSubWriter }
50
51(*
52  generic TElfSubWriter<_TElfRelocTable_,_TElfHdr_,_TElfSectHdr_,_TElfSymbol_,
53    _TPElfRela_,_TElfRela_,_TResHdr_,_TResInfoNode_> = class
54  ...
55  TElf32SubWriter = specialize TElfSubWriter<TElf32RelocTable,_TElf32Hdr_,
56    TElf32SectHdr,TElf32Symbol,PElf32Rela,TElf32Rela,TResHdr32,TResInfoNode32>;
57
58  TElf64SubWriter = specialize TElfSubWriter<TElf64RelocTable,_TElf64Hdr_,
59    TElf64SectHdr,TElf64Symbol,PElf64Rela,TElf64Rela,TResHdr64,TResInfoNode64>;
60*)
61
62  _TElfSubWriter_ = class(TAbstractElfSubWriter)
63  private
64    fRelocInfo :   TElfRelocInfo;
65    fRelocTable : _TElfRelocTable_;
66    procedure WriteEmptyElfHeader(aStream : TStream);
67    procedure WriteResHeader(aStream : TStream; aResources : TResources);
68    procedure WriteNodeInfos(aStream : TStream);
69    procedure WriteSectHeaders(aStream : TStream);
70    procedure FixElfHeader(aStream : TStream);
71    procedure WriteSymbols(aStream : TStream);
72    procedure WriteRelocations(aStream : TStream);
73  protected
74    procedure PrescanResourceTree; override;
75    procedure Write(aResources : TResources; aStream : TStream); override;
76    procedure WriteNodeInfo(aStream : TStream; aNode : TResourceTreeNode); override;
77  public
78    constructor Create(aParent : TElfResourceWriter; const aMachineType
79      : integer; const aOppositeEndianess : boolean); override;
80    destructor Destroy; override;
81  end;
82
83{ TElfRelocTable }
84
85function _TElfRelocTable_.GetCount: integer;
86begin
87  Result:=fList.Count;
88end;
89
90function _TElfRelocTable_.GetItem(index: integer): _TPElfRela_;
91begin
92  Result:=_TPElfRela_(fList[index]);
93end;
94
95constructor _TElfRelocTable_.Create(const fRelocInfo : TElfRelocInfo);
96begin
97  fList:=TFPList.Create;
98  fRelocType:=fRelocInfo.RelocType;
99  fSectionType:=fRelocInfo.SectionType;
100  case fSectionType of
101    SHT_REL  : begin
102                 fEntrySize:= sizeof(_TElfRel_);
103                 fSectionName:='.rel'+RsrcSectName;
104               end;
105    SHT_RELA : begin
106                 fEntrySize:= sizeof(_TElfRela_);
107                 fSectionName:='.rela'+RsrcSectName;
108               end;
109  end;
110end;
111
112destructor _TElfRelocTable_.Destroy;
113begin
114  Clear;
115  fList.Free;
116end;
117
118procedure _TElfRelocTable_.Add(const aOffset,aValue : _Tword_; aSymIdx : longword);
119var p : _TPElfRela_;
120begin
121  p:=GetMem(sizeof(_TElfRela_));
122  p^.Offset:=aOffset;
123  P^.Info:=aSymIdx;
124  {$IF _TElfRelocTable_=TElf64RelocTable}
125  P^.Info:=P^.Info shl 32;
126  P^.Info:=P^.Info or fRelocType;
127  {$ELSE}
128  P^.Info:=P^.Info shl 8;
129  P^.Info:=P^.Info or (fRelocType and $FF);
130  {$ENDIF}
131  p^.addend:=aValue;
132  fList.Add(p);
133end;
134
135procedure _TElfRelocTable_.Clear;
136var i : integer;
137    p : _TPElfRela_;
138begin
139  for i:=0 to fList.Count-1 do
140  begin
141    p:=_TPElfRela_(fList[i]);
142    FreeMem(p);
143  end;
144  fList.Clear;
145end;
146
147
148{ TElfSubWriter }
149
150procedure _TElfSubWriter_.PrescanResourceTree;
151begin
152  fResStringTable.Clear;
153  fRoot.SubDirRVA:=sizeof(_TResHdr_)+sizeof(_TResInfoNode_);
154  fResStringTable.StartOfs:=PrescanNode(fRoot,sizeof(_TResInfoNode_));
155  if fResStringTable.Used then
156    fDataCurOfs:=NextAligned(fDataAlignment,fResStringTable.StartOfs+fResStringTable.Size)
157  else
158    fDataCurOfs:=fResStringTable.StartOfs;
159end;
160
161procedure _TElfSubWriter_.WriteEmptyElfHeader(aStream: TStream);
162var hdr : _TElfHdr_;
163begin
164  FillByte(hdr,sizeof(hdr),0);
165  aStream.WriteBuffer(hdr,sizeof(hdr));
166end;
167
168procedure _TElfSubWriter_.WriteResHeader(aStream: TStream;
169  aResources: TResources);
170var hdr : _TResHdr_;
171begin
172  hdr.count:=aResources.Count;
173  hdr.usedhandles:=0;
174  hdr.handles:=0;
175
176  fSymbolTable.AddSection(RSRCSECT_IDX);
177  fSymbolTable.AddSection(HANDLESECT_IDX);
178  case fRelocInfo.SectionType of
179    SHT_REL  : hdr.rootptr:=sizeof(hdr);
180    SHT_RELA : hdr.rootptr:=0;
181  end;
182
183  fRelocTable.Add(0,sizeof(hdr),RSRCSECT_IDX);
184  fRelocTable.Add(sizeof(hdr.rootptr)+sizeof(hdr.count)+sizeof(hdr.usedhandles),0,HANDLESECT_IDX);
185  if fOppositeEndianess then
186  begin
187    hdr.rootptr:=SwapEndian(hdr.rootptr);
188    hdr.count:=SwapEndian(hdr.count);
189    //handles must be fixed later
190//    hdr.usedhandles:=SwapEndian(hdr.usedhandles);
191//    hdr.handles:=SwapEndian(hdr.handles);
192  end;
193  aStream.WriteBuffer(hdr,sizeof(hdr));
194end;
195
196procedure _TElfSubWriter_.WriteNodeInfos(aStream: TStream);
197begin
198  fCurOfs:=sizeof(_TResHdr_);
199  WriteNodeInfo(aStream,fRoot);
200  WriteSubNodes(aStream,fRoot);
201end;
202
203procedure _TElfSubWriter_.WriteNodeInfo(aStream: TStream;
204  aNode: TResourceTreeNode);
205var infonode : _TResInfoNode_;
206begin
207  if aNode.Desc.DescType=dtID then
208    infonode.nameid:=aNode.Desc.ID
209  else
210  begin
211    infonode.nameid:=fResStringTable.StartOfs+aNode.NameRVA;
212    fRelocTable.Add(fCurOfs,infonode.nameid,RSRCSECT_IDX);
213    if fRelocInfo.SectionType=SHT_RELA then infonode.nameid:=0;
214  end;
215  infonode.ncount:=aNode.NamedCount;
216  if aNode.IsLeaf then
217  begin
218    infonode.idcountsize:=aNode.Data.RawData.Size;
219    infonode.subptr:=fDataCurOfs;
220    fDataCurOfs:=NextAligned(fDataAlignment,fDataCurOfs+infonode.idcountsize);
221  end
222  else
223  begin
224    infonode.idcountsize:=aNode.IDCount;
225    infonode.subptr:=aNode.SubDirRVA;
226  end;
227  fRelocTable.Add(
228    fCurOfs+sizeof(infonode.nameid)+sizeof(infonode.ncount)+
229    sizeof(infonode.idcountsize),infonode.subptr,RSRCSECT_IDX);
230  if fRelocInfo.SectionType=SHT_RELA then infonode.subptr:=0;
231  if fOppositeEndianess then
232  begin
233    infonode.nameid:=SwapEndian(infonode.nameid);
234    infonode.ncount:=SwapEndian(infonode.ncount);
235    infonode.idcountsize:=SwapEndian(infonode.idcountsize);
236    infonode.subptr:=SwapEndian(infonode.subptr);
237  end;
238  aStream.WriteBuffer(infonode,sizeof(infonode));
239  inc(fCurOfs,sizeof(infonode));
240end;
241
242procedure _TElfSubWriter_.WriteSectHeaders(aStream: TStream);
243var i : integer;
244    orig : PElf64SectHdr;
245    hdr : _TElfSectHdr_;
246begin
247  Align(fDataAlignment,aStream);
248  fSectHdrOffset:=aStream.Position;
249  for i:=0 to fSections.Count-1 do
250  begin
251    orig:=fSections[i];
252    {$IF _TElfSubWriter_=TElf64SubWriter}
253    hdr:=orig^;
254    {$ELSE}
255    hdr.NameIdx:=orig^.NameIdx;
256    hdr._Type:=orig^._Type;
257    hdr.Flags:=orig^.Flags;
258    hdr.Address:=orig^.Address;
259    hdr.Offset:=orig^.Offset;
260    hdr.Size:=orig^.Size;
261    hdr.Link:=orig^.Link;
262    hdr.Info:=orig^.Info;
263    hdr.AddrAlign:=orig^.AddrAlign;
264    hdr.EntSize:=orig^.EntSize;
265    {$ENDIF}
266
267    if fOppositeEndianess then
268    begin
269      hdr.NameIdx:=SwapEndian(hdr.NameIdx);
270      hdr._Type:=SwapEndian(hdr._Type);
271      hdr.Flags:=SwapEndian(hdr.Flags);
272      hdr.Address:=SwapEndian(hdr.Address);
273      hdr.Offset:=SwapEndian(hdr.Offset);
274      hdr.Size:=SwapEndian(hdr.Size);
275      hdr.Link:=SwapEndian(hdr.Link);
276      hdr.Info:=SwapEndian(hdr.Info);
277      hdr.AddrAlign:=SwapEndian(hdr.AddrAlign);
278      hdr.EntSize:=SwapEndian(hdr.EntSize);
279    end;
280
281    aStream.WriteBuffer(hdr,sizeof(hdr));
282  end;
283end;
284
285procedure _TElfSubWriter_.FixElfHeader(aStream: TStream);
286var hdr : _TElfHdr_;
287begin
288  hdr._Type:=ET_REL;
289  hdr.Machine:=fMachineType;
290  hdr.Version:=EV_CURRENT;
291  hdr.Entry:=0;
292  hdr.ProgHdrOffset:=0;
293  hdr.SectHdrOffset:=fSectHdrOffset;
294  hdr.Flags:=fMachineFlags;
295  hdr.HdrSize:=sizeof(_TElfHdr_)+sizeof(TElfIdent);
296  hdr.ProgHdrEntrySize:=0;
297  hdr.ProgHdrNum:=0;
298  hdr.SectHdrEntrySize:=sizeof(_TElfSectHdr_);
299  hdr.SectHdrNum:=fSections.Count;
300  hdr.NameTableIndex:=fShStrTabIdx;
301
302  if fOppositeEndianess then
303  begin
304    hdr._Type:=SwapEndian(hdr._Type);
305    hdr.Machine:=SwapEndian(hdr.Machine);
306    hdr.Version:=SwapEndian(hdr.Version);
307    hdr.Entry:=SwapEndian(hdr.Entry);
308    hdr.ProgHdrOffset:=SwapEndian(hdr.ProgHdrOffset);
309    hdr.SectHdrOffset:=SwapEndian(hdr.SectHdrOffset);
310    hdr.Flags:=SwapEndian(hdr.Flags);
311    hdr.HdrSize:=SwapEndian(hdr.HdrSize);
312    hdr.ProgHdrEntrySize:=SwapEndian(hdr.ProgHdrEntrySize);
313    hdr.ProgHdrNum:=SwapEndian(hdr.ProgHdrNum);
314    hdr.SectHdrEntrySize:=SwapEndian(hdr.SectHdrEntrySize);
315    hdr.SectHdrNum:=SwapEndian(hdr.SectHdrNum);
316    hdr.NameTableIndex:=SwapEndian(hdr.NameTableIndex);
317  end;
318
319  aStream.Position:=sizeof(TElfIdent);
320  aStream.WriteBuffer(hdr,sizeof(hdr));
321end;
322
323procedure _TElfSubWriter_.WriteSymbols(aStream: TStream);
324var i : integer;
325    orig : PElf64Symbol;
326    sym : _TElfSymbol_;
327    startpos : int64;
328begin
329  Align(fDataAlignment,aStream);
330  startpos:=aStream.Position;
331  for i:=0 to fSymbolTable.Count-1 do
332  begin
333    orig:=fSymbolTable[i];
334    {$IF _TElfSubWriter_=TElf64SubWriter}
335    sym:=orig^;
336    {$ELSE}
337    sym.Name:=orig^.Name;
338    sym.Value:=orig^.Value;
339    sym.Size:=orig^.Size;
340    sym.Info:=orig^.Info;
341    sym.Other:=orig^.Other;
342    sym.SectIdx:=orig^.SectIdx;
343    {$ENDIF}
344
345    if fOppositeEndianess then
346    begin
347      sym.Name:=SwapEndian(sym.Name);
348      sym.Value:=SwapEndian(sym.Value);
349      sym.Size:=SwapEndian(sym.Size);
350      sym.SectIdx:=SwapEndian(sym.SectIdx);
351    end;
352
353    aStream.WriteBuffer(sym,sizeof(sym));
354  end;
355
356  fSymTabIdx:=fSections.Add('.symtab',SHT_SYMTAB,0,startpos,
357    fSymbolTable.Count*sizeof(_TElfSymbol_),sizeof(_TElfSymbol_),fSymStrTabIdx,
358    fSymbolTable.FirstGlobal,fDataAlignment);
359end;
360
361procedure _TElfSubWriter_.WriteRelocations(aStream: TStream);
362var orig : _TPElfRela_;
363    rel : _TElfRela_;
364    startpos : int64;
365    i : integer;
366begin
367  Align(fDataAlignment,aStream);
368  startpos:=aStream.Position;
369  for i:=0 to fRelocTable.Count-1 do
370  begin
371    orig:=fRelocTable[i];
372    rel:=orig^;
373
374    if fOppositeEndianess then
375    begin
376      rel.Offset:=SwapEndian(rel.Offset);
377      rel.Info:=SwapEndian(rel.Info);
378      rel.Addend:=SwapEndian(rel.Addend);
379    end;
380
381    aStream.WriteBuffer(rel,fRelocTable.EntrySize);
382  end;
383
384  fSections.Add(fRelocTable.SectionName,fRelocTable.SectionType,0,startpos,
385    fRelocTable.Count*fRelocTable.EntrySize,fRelocTable.EntrySize,
386    fSymTabIdx,1,fDataAlignment);
387end;
388
389procedure _TElfSubWriter_.Write(aResources: TResources; aStream: TStream);
390begin
391  fRoot:=TRootResTreeNode(fParent.GetTree(aResources));
392  WriteEmptyElfHeader(aStream);
393  fSectionStart:=aStream.Position;
394  PrescanResourceTree;
395  WriteResHeader(aStream,aResources);
396  WriteNodeInfos(aStream);
397  WriteResStringTable(aStream);
398  WriteRawData(aStream);
399  fSections.Add(RsrcSectName, SHT_PROGBITS,SHF_ALLOC or SHF_WRITE,fSectionStart,
400    fDataCurOfs,fDataAlignment);
401  AddEmptySections(aResources,aStream);
402  fSymbolTable.AddGlobal('FPC_RESSYMBOL',0,0,STT_OBJECT,RSRCSECT_IDX);
403  WriteStrTab(aStream);
404  WriteSymbols(aStream);
405  WriteRelocations(aStream);
406  WriteShStrTab(aStream);
407  WriteSectHeaders(aStream);
408  FixElfHeader(aStream);
409end;
410
411constructor _TElfSubWriter_.Create(aParent : TElfResourceWriter; const
412  aMachineType: integer; const aOppositeEndianess: boolean);
413begin
414  inherited Create(aParent, aMachineType, aOppositeEndianess);
415
416  with fRelocInfo do
417    case aMachineType of
418      EM_386    : begin RelocType:=R_386_32;        SectionType:=SHT_REL;  end;
419      EM_PPC    : begin RelocType:=R_PPC_ADDR32;    SectionType:=SHT_RELA; end;
420      EM_ARM    : begin RelocType:=R_ARM_ABS32;     SectionType:=SHT_REL;  end;
421      EM_AARCH64: begin RelocType:=R_AARCH64_ABS64; SectionType:=SHT_RELA; end;
422      EM_68K    : begin RelocType:=R_68K_32;        SectionType:=SHT_RELA; end;
423      EM_SPARC  : begin RelocType:=R_SPARC_32;      SectionType:=SHT_RELA; end;
424      EM_X86_64 : begin RelocType:=R_x86_64_64;     SectionType:=SHT_RELA; end;
425      EM_PPC64  : begin RelocType:=R_PPC64_ADDR64;  SectionType:=SHT_RELA; end;
426      EM_ALPHA  : begin RelocType:=R_ALPHA_REFQUAD; SectionType:=SHT_RELA; end;
427      EM_IA_64  : begin RelocType:=R_IA64_DIR64LSB; SectionType:=SHT_RELA; end;
428      EM_MIPS   : begin RelocType:=R_MIPS_32;      SectionType:=SHT_RELA; end;
429      else
430        raise EElfResourceWriterUnknownMachineException.Create('');
431    end;
432
433  fRelocTable:=_TElfRelocTable_.Create(fRelocInfo);
434  {$IF _TElfSubWriter_=TElf64SubWriter}
435  fDataAlignment:=8;
436  {$ELSE}
437  fDataAlignment:=4;
438  {$ENDIF}
439  if aMachineType=EM_IA_64 then fMachineFlags:=EF_IA_64_ABI64
440  else fMachineFlags:=0;
441end;
442
443destructor _TElfSubWriter_.Destroy;
444begin
445  fRelocTable.Free;
446  inherited Destroy;
447end;
448
449