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