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 16unit elfwriter; 17 18{$MODE OBJFPC} {$H+} 19 20interface 21 22uses 23 Classes, SysUtils, resource, elfconsts, elftypes; 24 25type 26 EElfResourceWriterException = class(EResourceWriterException); 27 EElfResourceWriterUnknownMachineException = class(EElfResourceWriterException); 28 EElfResourceWriterUnknownClassException = class(EElfResourceWriterException); 29 EElfResourceWriterUnknownSectionException = class(EElfResourceWriterException); 30 31type 32 { TElfResourceWriter } 33 34 TElfResourceWriter = class (TAbstractResourceWriter) 35 private 36 fExtensions : string; 37 fDescription : string; 38 fMachineTypeInt : integer; 39 fMachineType : TElfMachineType; 40 fOrder : byte; 41 fBits : byte; 42 fNativeOrder : integer; 43 fOppositeEndianess : boolean; 44 procedure SetDefaultTarget; 45 procedure SetMachineType(const aMachineType : TElfMachineType); 46 47 procedure WriteElfIdent(aStream : TStream); 48 protected 49 function GetExtensions : string; override; 50 function GetDescription : string; override; 51 procedure Write(aResources : TResources; aStream : TStream); override; 52 public 53 constructor Create; override; 54 destructor Destroy; override; 55 property MachineType : TElfMachineType read fMachineType write SetMachineType; 56 end; 57 58 59implementation 60 61uses resourcetree, strtable, fpcrestypes; 62 63type 64 65 { TElfSections } 66 67 TElfSections = class 68 private 69 fList : TFPList; 70 fStringTable : TObjectStringTable; 71 function GetCount : integer; 72 function GetItem(index : integer) : PElf64SectHdr; 73 protected 74 public 75 constructor Create(aStringTable : TObjectStringTable); 76 destructor Destroy; override; 77 function Add(const aName: string; const aType, aFlags : longword; 78 const aOffset, aSize : qword; const aAddrAlign : longword) : integer; overload; 79 function Add(const aName: string; const aType, aFlags : longword; 80 const aOffset, aSize, aEntSize : qword; const aLink, aInfo,aAddrAlign 81 : longword) : integer; overload; 82 procedure Clear; 83 property Count : integer read GetCount; 84 property Items[index : integer] : PElf64SectHdr read GetItem; default; 85 end; 86 87 { TElfSymbolTable } 88 89 TElfSymbolTable = class 90 private 91 fList : TFPList; 92 fSectFree : integer; 93 fLocFree : integer; 94 fStringTable : TObjectStringTable; 95 function CreateSym(const aName : string; const aValue, aSize : qword; 96 const aBind, aType : byte; const aSectIdx : integer) : PElf64Symbol; 97 procedure Clear; 98 function GetCount : integer; 99 function GetItem(index : integer) : PElf64Symbol; 100 protected 101 public 102 constructor Create(aStringTable : TObjectStringTable); 103 destructor Destroy; override; 104 procedure AddSection(const aSectIdx : integer); 105 procedure AddLocal(const aName : string; const aValue, aSize : qword; 106 const aType : byte; const aSectIdx : integer); 107 procedure AddGlobal(const aName : string; const aValue, aSize : qword; 108 const aType : byte; const aSectIdx : integer); 109 property Count : integer read GetCount; 110 property Items[index : integer] : PElf64Symbol read GetItem; default; 111 property FirstGlobal : integer read fLocFree; 112 end; 113 114 { TAbstractElfSubWriter } 115 116 TAbstractElfSubWriter = class 117 private 118 protected 119 fParent : TElfResourceWriter; 120 fOppositeEndianess : boolean; 121 fMachineType : integer; 122 fDataAlignment : longword; 123 fMachineFlags : longword; 124 fRoot : TRootResTreeNode; 125 fSectStringTable : TObjectStringTable; 126 fSymStringTable : TObjectStringTable; 127 fResStringTable : TResStringTable; 128 fSymbolTable : TElfSymbolTable; 129 fSections : TElfSections; 130 fShStrTabIdx : integer; 131 fSymStrTabIdx : integer; 132 fSymTabIdx : integer; 133 fSectHdrOffset : qword; 134 fCurOfs : longword; 135 fDataCurOfs : longword; 136 fSectionStart : qword; 137 procedure Align(aBound : integer; aStream : TStream); 138 function NextAligned(aBound, aValue : longword) : longword; 139 procedure PrescanResourceTree; virtual; abstract; 140 function PrescanNode(aNode : TResourceTreeNode; aNodeSize : longword) : longword; 141 procedure WriteNodeInfo(aStream : TStream; aNode : TResourceTreeNode); virtual; abstract; 142 procedure WriteSubNodes(aStream : TStream; aNode : TResourceTreeNode); 143 procedure WriteResStringTable(aStream : TStream); 144 procedure WriteRawData(aStream : TStream); 145 procedure WriteResData(aStream : TStream; aNode : TResourceTreeNode); 146 procedure AddEmptySections(aResources : TResources; aStream : TStream); 147 procedure WriteStrTab(aStream : TStream); 148 procedure WriteShStrTab(aStream : TStream); 149 procedure Write(aResources : TResources; aStream : TStream); virtual; abstract; 150 public 151 constructor Create(aParent : TElfResourceWriter; const aMachineType : integer; 152 const aOppositeEndianess : boolean); virtual; 153 destructor Destroy; override; 154 end; 155 156type 157 TElfRelocInfo = record 158 RelocType : longword; 159 SectionType : integer; 160 end; 161(* 162Almost all differences in 32 and 64 bit elf files lie in record sizes. 163Generics don't work with record types, so use macros to do this task 164(uglier, but should be the same) 165*) 166 167{$MACRO ON} 168 169//Define TElf32RelocTable and TElf32SubWriter 170 171{$DEFINE _TElfRelocTable_:=TElf32RelocTable} 172{$DEFINE _TPElfRela_:=PElf32Rela} 173{$DEFINE _TElfRela_:=TElf32Rela} 174{$DEFINE _TPElfRel_:=PElf32Rel} 175{$DEFINE _TElfRel_:=TElf32Rel} 176{$DEFINE _Tword_:=longword} 177{$DEFINE _TElfSubWriter_:=TElf32SubWriter} 178{$DEFINE _TElfHdr_:=TElf32Hdr} 179{$DEFINE _TElfSectHdr_:=TElf32SectHdr} 180{$DEFINE _TElfSymbol_:=TElf32Symbol} 181{$DEFINE _TResHdr_:=TResHdr32} 182{$DEFINE _TResInfoNode_:=TResInfoNode32} 183{$INCLUDE elfsubwriter.inc} 184 185 186//Define TElf64RelocTable and TElf32SubWriter 187 188{$DEFINE _TElfRelocTable_:=TElf64RelocTable} 189{$DEFINE _TPElfRela_:=PElf64Rela} 190{$DEFINE _TElfRela_:=TElf64Rela} 191{$DEFINE _TPElfRel_:=PElf64Rel} 192{$DEFINE _TElfRel_:=TElf64Rel} 193{$DEFINE _Tword_:=qword} 194{$DEFINE _TElfSubWriter_:=TElf64SubWriter} 195{$DEFINE _TElfHdr_:=TElf64Hdr} 196{$DEFINE _TElfSectHdr_:=TElf64SectHdr} 197{$DEFINE _TElfSymbol_:=TElf64Symbol} 198{$DEFINE _TResHdr_:=TResHdr64} 199{$DEFINE _TResInfoNode_:=TResInfoNode64} 200{$INCLUDE elfsubwriter.inc} 201 202 203//Clean all this stuff... 204 205{$UNDEF _TElfRelocTable_} 206{$UNDEF _TPElfRela_} 207{$UNDEF _TElfRela_} 208{$UNDEF _TPElfRel_} 209{$UNDEF _TElfRel_} 210{$UNDEF _Tword_} 211{$UNDEF _TElfSubWriter_} 212{$UNDEF _TElfHdr_} 213{$UNDEF _TElfSectHdr_} 214{$UNDEF _TElfSymbol_} 215{$UNDEF _TResHdr_} 216{$UNDEF _TResInfoNode_} 217 218 219{ TElfSections } 220 221function TElfSections.GetCount: integer; 222begin 223 Result:=fList.Count; 224end; 225 226function TElfSections.GetItem(index: integer): PElf64SectHdr; 227begin 228 Result:=PElf64SectHdr(fList[index]); 229end; 230 231constructor TElfSections.Create(aStringTable : TObjectStringTable); 232begin 233 fList:=TFPList.Create; 234 fStringTable:=aStringTable; 235 Add('',0,0,0,0,0); //empty section 236end; 237 238destructor TElfSections.Destroy; 239var i : integer; 240 p : PElf64SectHdr; 241begin 242 for i:=0 to fList.Count-1 do 243 begin 244 p:=PElf64SectHdr(fList[i]); 245 FreeMem(p); 246 end; 247 248 fList.Free; 249end; 250 251function TElfSections.Add(const aName: string; const aType, aFlags : longword; 252 const aOffset, aSize : qword; const aAddrAlign : longword) : integer; 253begin 254 Result:=Add(aName,aType,aFlags,aOffset,aSize,0,0,0,aAddrAlign); 255end; 256 257function TElfSections.Add(const aName: string; const aType, aFlags: longword; 258 const aOffset, aSize, aEntSize: qword; const aLink, aInfo, aAddrAlign: longword): integer; 259var p : PElf64SectHdr; 260begin 261 Result:=fList.Count; 262 p:=GetMem(sizeof(TElf64SectHdr)); 263 p^.NameIdx:=fStringTable.Add(aName); 264 p^._Type:=aType; 265 p^.Flags:=aFlags; 266 p^.Address:=0; 267 p^.Offset:=aOffset;; 268 p^.Size:=aSize; 269 p^.Link:=aLink; 270 p^.Info:=aInfo; 271 p^.AddrAlign:=aAddrAlign; 272 p^.EntSize:=aEntSize; 273 fList.Add(p); 274end; 275 276procedure TElfSections.Clear; 277var i : integer; 278 p, first : PElf64SectHdr; 279begin 280 first:=PElf64SectHdr(fList[0]); 281 for i:=1 to fList.Count-1 do 282 begin 283 p:=PElf64SectHdr(fList[i]); 284 FreeMem(p); 285 end; 286 fList.Clear; 287 fList.Add(first); 288end; 289 290{ TElfSymbolTable } 291 292constructor TElfSymbolTable.Create(aStringTable: TObjectStringTable); 293var p : PElf64Symbol; 294begin 295 fList:=TFPList.Create; 296 fStringTable:=aStringTable; 297 p:=CreateSym('',0,0,0,0,0); 298 fList.Add(p); 299 fSectFree:=1; 300 fLocFree:=1; 301end; 302 303destructor TElfSymbolTable.Destroy; 304begin 305 Clear; 306 fList.Free; 307end; 308 309procedure TElfSymbolTable.AddSection(const aSectIdx: integer); 310var p : PElf64Symbol; 311begin 312 p:=CreateSym('',0,0,STB_LOCAL,STT_SECTION,aSectIdx); 313 if fSectFree=fList.Count then 314 fList.Add(p) 315 else 316 fList.Insert(fSectFree,p); 317 inc(fSectFree); 318 inc(fLocFree); 319end; 320 321procedure TElfSymbolTable.AddLocal(const aName: string; const aValue, 322 aSize: qword; const aType: byte; const aSectIdx: integer); 323var p : PElf64Symbol; 324begin 325 p:=CreateSym(aName,aValue,aSize,STB_LOCAL,aType,aSectIdx); 326 if fLocFree=fList.Count then 327 fList.Add(p) 328 else 329 fList.Insert(fLocFree,p); 330 inc(fLocFree); 331end; 332 333procedure TElfSymbolTable.AddGlobal(const aName: string; const aValue, 334 aSize: qword; const aType: byte; const aSectIdx: integer); 335var p : PElf64Symbol; 336begin 337 p:=CreateSym(aName,aValue,aSize,STB_GLOBAL,aType,aSectIdx); 338 fList.Add(p) 339end; 340 341procedure TElfSymbolTable.Clear; 342var p : PElf64Symbol; 343 i : integer; 344begin 345 for i:=0 to fList.Count-1 do 346 begin 347 p:=PElf64Symbol(fList[i]); 348 FreeMem(p); 349 end; 350 fList.Clear; 351end; 352 353function TElfSymbolTable.GetCount: integer; 354begin 355 Result:=fList.Count; 356end; 357 358function TElfSymbolTable.GetItem(index: integer): PElf64Symbol; 359begin 360 Result:=PElf64Symbol(fList[index]); 361end; 362 363function TElfSymbolTable.CreateSym(const aName : string; const aValue, aSize : qword; 364 const aBind, aType : byte; const aSectIdx : integer) : PElf64Symbol; 365var p : PElf64Symbol; 366begin 367 p:=GetMem(sizeof(TElf64Symbol)); 368 p^.Name:=fStringTable.Add(aName); 369 p^.Value:=aValue; 370 p^.Size:=aSize; 371 p^.Info:=aBind shl 4; 372 p^.Info:=p^.Info or (aType and $0F); 373 p^.Other:=0; 374 p^.SectIdx:=aSectIdx; 375 Result:=p; 376end; 377 378{ TAbstractElfSubWriter } 379 380procedure TAbstractElfSubWriter.Align(aBound : integer; aStream : TStream); 381var topad,tmp : integer; 382 qw : qword; 383begin 384 qw:=0; 385 topad:=aBound-(aStream.Position mod aBound); 386 if topad<>aBound then 387 while topad>0 do 388 begin 389 if topad>8 then tmp:=8 else tmp:=topad; 390 aStream.WriteBuffer(qw,tmp); 391 dec(topad,tmp); 392 end; 393end; 394 395function TAbstractElfSubWriter.NextAligned(aBound, aValue : longword) : longword; 396var topad : longword; 397begin 398 Result:=aValue; 399 topad:=aBound-(aValue mod aBound); 400 if topad<>aBound then inc(Result,topad); 401end; 402 403function TAbstractElfSubWriter.PrescanNode(aNode: TResourceTreeNode; 404 aNodeSize: longword): longword; 405var curofs : longword; 406 i : integer; 407 subnode : TResourceTreeNode; 408begin 409 if aNode.IsLeaf then 410 begin 411 Result:=aNode.SubDirRVA; 412 exit; 413 end; 414 415 if aNode.Desc.DescType=dtName then 416 aNode.NameRVA:=fResStringTable.Add(aNode.Desc.Name); 417 418 //first node subnodes begin at curofs (after all node headers) 419 curofs:=aNode.SubDirRva+(aNode.NamedCount+aNode.IDCount)*aNodeSize; 420 for i:=0 to aNode.NamedCount-1 do 421 begin 422 subnode:=aNode.NamedEntries[i]; 423 subnode.SubDirRVA:=curofs; 424 curofs:=PrescanNode(subnode,aNodeSize); 425 end; 426 for i:=0 to aNode.IDCount-1 do 427 begin 428 subnode:=aNode.IDEntries[i]; 429 subnode.SubDirRVA:=curofs; 430 curofs:=PrescanNode(subnode,aNodeSize); 431 end; 432 Result:=curofs; 433end; 434 435procedure TAbstractElfSubWriter.WriteSubNodes(aStream: TStream; 436 aNode: TResourceTreeNode); 437var i : integer; 438begin 439 for i:=0 to aNode.NamedCount-1 do 440 WriteNodeInfo(aStream,aNode.NamedEntries[i]); 441 for i:=0 to aNode.IDCount-1 do 442 WriteNodeInfo(aStream,aNode.IDEntries[i]); 443 444 for i:=0 to aNode.NamedCount-1 do 445 WriteSubNodes(aStream,aNode.NamedEntries[i]); 446 for i:=0 to aNode.IDCount-1 do 447 WriteSubNodes(aStream,aNode.IDEntries[i]); 448end; 449 450procedure TAbstractElfSubWriter.WriteResStringTable(aStream: TStream); 451begin 452 if fResStringTable.Used then 453 fResStringTable.WriteToStream(aStream); 454 Align(fDataAlignment,aStream); 455end; 456 457 458procedure TAbstractElfSubWriter.WriteRawData(aStream: TStream); 459begin 460 WriteResData(aStream,fRoot); 461end; 462 463procedure TAbstractElfSubWriter.WriteResData(aStream: TStream; 464 aNode: TResourceTreeNode); 465var rawdata : TStream; 466 i : integer; 467begin 468 if aNode.IsLeaf then 469 begin 470 rawdata:=aNode.Data.RawData; 471 rawdata.Position:=0; 472 aStream.CopyFrom(rawdata,rawdata.Size); 473 Align(fDataAlignment,aStream); 474 exit; 475 end; 476 for i:=0 to aNode.NamedCount-1 do 477 WriteResData(aStream,aNode.NamedEntries[i]); 478 for i:=0 to aNode.IDCount-1 do 479 WriteResData(aStream,aNode.IDEntries[i]); 480end; 481 482procedure TAbstractElfSubWriter.AddEmptySections(aResources : TResources; aStream: TStream); 483begin 484 Align(fDataAlignment,aStream); 485 fSections.Add(HandlesSectName,SHT_NOBITS,SHF_ALLOC or SHF_WRITE, 486 aStream.Position,fDataAlignment*aResources.Count,fDataAlignment); 487 fSections.Add('.text',SHT_PROGBITS,SHF_ALLOC or SHF_EXECINSTR,aStream.Position,0,4); 488 fSections.Add('.data',SHT_PROGBITS,SHF_ALLOC or SHF_WRITE,aStream.Position,0,4); 489 fSections.Add('.bss', SHT_NOBITS,SHF_ALLOC or SHF_WRITE,aStream.Position,0,4); 490 fSections.Add('.note.GNU-stack', SHT_PROGBITS,0,aStream.Position,0,1); 491end; 492 493procedure TAbstractElfSubWriter.WriteStrTab(aStream: TStream); 494begin 495 fSymStrTabIdx:=fSections.Add('.strtab',SHT_STRTAB,0,aStream.Position, 496 fSymStringTable.Size,1); 497 fSymStringTable.WriteToStream(aStream); 498end; 499 500procedure TAbstractElfSubWriter.WriteShStrTab(aStream: TStream); 501const namelen = length('.shstrtab')+1; 502begin 503 fShStrTabIdx:=fSections.Add('.shstrtab',SHT_STRTAB,0,aStream.Position, 504 fSectStringTable.Size+namelen,1); 505 fSectStringTable.WriteToStream(aStream); 506end; 507 508constructor TAbstractElfSubWriter.Create(aParent : TElfResourceWriter; 509 const aMachineType: integer; const aOppositeEndianess: boolean); 510begin 511 fMachineType:=aMachineType; 512 fOppositeEndianess:=aOppositeEndianess; 513 fRoot:=nil; 514 fParent:=aParent; 515 fSectStringTable:=TObjectStringTable.Create(nil,0); 516 fSymStringTable:=TObjectStringTable.Create(nil,0); 517 fResStringTable:=TResStringTable.Create; 518 fSymbolTable:=TElfSymbolTable.Create(fSymStringTable); 519 fSections:=TElfSections.Create(fSectStringTable); 520 fShStrTabIdx:=0; 521 fSymStrTabIdx:=0; 522 fSectHdrOffset:=0; 523 fCurOfs:=0; 524 fDataCurOfs:=0; 525 fSectionStart:=0; 526end; 527 528destructor TAbstractElfSubWriter.Destroy; 529begin 530 fSectStringTable.Free; 531 fSymStringTable.Free; 532 fResStringTable.Free; 533 fSymbolTable.Free; 534 fSections.Free; 535end; 536 537{ TElfResourceWriter } 538 539procedure TElfResourceWriter.SetDefaultTarget; 540begin 541 {$INCLUDE elfdefaulttarget.inc} 542end; 543 544procedure TElfResourceWriter.SetMachineType(const aMachineType: TElfMachineType); 545begin 546 case aMachineType of 547 emtsparc : begin fMachineTypeInt:=EM_SPARC; fBits:=ELFCLASS32; fOrder:=ELFDATA2MSB; end; 548 emti386 : begin fMachineTypeInt:=EM_386; fBits:=ELFCLASS32; fOrder:=ELFDATA2LSB; end; 549 emtm68k : begin fMachineTypeInt:=EM_68K; fBits:=ELFCLASS32; fOrder:=ELFDATA2MSB; end; 550 emtppc : begin fMachineTypeInt:=EM_PPC; fBits:=ELFCLASS32; fOrder:=ELFDATA2MSB; end; 551 emtppc64 : begin fMachineTypeInt:=EM_PPC64; fBits:=ELFCLASS64;fOrder:=ELFDATA2MSB; end; 552 emtppc64le: begin fMachineTypeInt:=EM_PPC64; fBits:=ELFCLASS64;fOrder:=ELFDATA2LSB; end; 553 emtarm : begin fMachineTypeInt:=EM_ARM; fBits:=ELFCLASS32; fOrder:=ELFDATA2LSB; end; 554 emtarmeb : begin fMachineTypeInt:=EM_ARM; fBits:=ELFCLASS32; fOrder:=ELFDATA2MSB; end; 555 emtaarch64: begin fMachineTypeInt:=EM_AARCH64; fBits:=ELFCLASS64; fOrder:=ELFDATA2LSB; end; 556 emtalpha : begin fMachineTypeInt:=EM_ALPHA; fBits:=ELFCLASS64; fOrder:=ELFDATA2LSB; end; 557 emtia64 : begin fMachineTypeInt:=EM_IA_64; fBits:=ELFCLASS64; fOrder:=ELFDATA2LSB; end; 558 emtx86_64 : begin fMachineTypeInt:=EM_X86_64; fBits:=ELFCLASS64; fOrder:=ELFDATA2LSB; end; 559 emtmips : begin fMachineTypeInt:=EM_MIPS; fBits:=ELFCLASS32; fOrder:=ELFDATA2MSB; end; 560 emtmipsel : begin fMachineTypeInt:=EM_MIPS; fBits:=ELFCLASS32; fOrder:=ELFDATA2LSB; end 561 else 562 raise EElfResourceWriterUnknownMachineException.Create(''); 563 end; 564 fMachineType:=aMachineType; 565 fOppositeEndianess:=fNativeOrder<>fOrder; 566end; 567 568procedure TElfResourceWriter.WriteElfIdent(aStream: TStream); 569var ident : TElfIdent; 570begin 571 ident.Magic:=ELFMAGIC; 572 ident.ElfClass:=fBits; 573 ident.ElfData:=fOrder; 574 ident.ElfVersion:=EV_CURRENT; 575 ident.OsAbi:=ELFOSABI_NONE; // UNIX System V ABI 576 ident.AbiVersion:=0; 577 FillByte(ident.Padding[9],length(ident.Padding),0); 578 579 aStream.WriteBuffer(ident,sizeof(ident)); 580end; 581 582function TElfResourceWriter.GetExtensions: string; 583begin 584 Result:=fExtensions; 585end; 586 587function TElfResourceWriter.GetDescription: string; 588begin 589 Result:=fDescription; 590end; 591 592procedure TElfResourceWriter.Write(aResources: TResources; aStream: TStream); 593var subwriter : TAbstractElfSubWriter; 594begin 595 WriteElfIdent(aStream); 596 case fBits of 597 ELFCLASS32 : subwriter:=TElf32SubWriter.Create(self,fMachineTypeInt,fOppositeEndianess); 598 ELFCLASS64 : subwriter:=TElf64SubWriter.Create(self,fMachineTypeInt,fOppositeEndianess) 599 else 600 raise EElfResourceWriterUnknownClassException.Create(''); 601 end; 602 try 603 subwriter.Write(aResources,aStream); 604 finally 605 subwriter.Free; 606 end; 607end; 608 609constructor TElfResourceWriter.Create; 610begin 611 fExtensions:='.o .or'; 612 fDescription:='ELF resource writer'; 613 SetDefaultTarget; 614end; 615 616destructor TElfResourceWriter.Destroy; 617begin 618 619end; 620 621initialization 622 TResources.RegisterWriter('.o',TElfResourceWriter); 623 TResources.RegisterWriter('.or',TElfResourceWriter); 624 625end. 626