mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 02:19:22 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			3401 lines
		
	
	
		
			118 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			3401 lines
		
	
	
		
			118 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
    Copyright (c) 1998-2006 by Peter Vreman
 | 
						|
 | 
						|
    Contains the binary elf writer
 | 
						|
 | 
						|
    This program is free software; you can redistribute it and/or modify
 | 
						|
    it under the terms of the GNU General Public License as published by
 | 
						|
    the Free Software Foundation; either version 2 of the License, or
 | 
						|
    (at your option) any later version.
 | 
						|
 | 
						|
    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.  See the
 | 
						|
    GNU General Public License for more details.
 | 
						|
 | 
						|
    You should have received a copy of the GNU General Public License
 | 
						|
    along with this program; if not, write to the Free Software
 | 
						|
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
						|
 | 
						|
 ****************************************************************************
 | 
						|
}
 | 
						|
unit ogelf;
 | 
						|
 | 
						|
{$i fpcdefs.inc}
 | 
						|
 | 
						|
interface
 | 
						|
 | 
						|
    uses
 | 
						|
       { common }
 | 
						|
       cclasses,globtype,
 | 
						|
       { target }
 | 
						|
       systems,
 | 
						|
       { assembler }
 | 
						|
       cpuinfo,cpubase,aasmbase,aasmtai,aasmdata,assemble,
 | 
						|
       { ELF definitions }
 | 
						|
       elfbase,
 | 
						|
       { output }
 | 
						|
       ogbase,
 | 
						|
       owbase;
 | 
						|
 | 
						|
    type
 | 
						|
{$ifdef cpu64bitaddr}
 | 
						|
      TElfsechdr = TElf64sechdr;
 | 
						|
{$else cpu64bitaddr}
 | 
						|
      TElfsechdr = TElf32sechdr;
 | 
						|
{$endif cpu64bitaddr}
 | 
						|
 | 
						|
       TElfObjSection = class(TObjSection)
 | 
						|
       public
 | 
						|
          shstridx,
 | 
						|
          shtype,
 | 
						|
          shflags,
 | 
						|
          shlink,
 | 
						|
          shinfo,
 | 
						|
          shentsize : longint;
 | 
						|
          constructor create(AList:TFPHashObjectList;const Aname:string;Aalign:shortint;Aoptions:TObjSectionOptions);override;
 | 
						|
          constructor create_ext(aobjdata:TObjData;const Aname:string;Ashtype,Ashflags:longint;Aalign:shortint;Aentsize:longint);
 | 
						|
          constructor create_reloc(aobjdata:TObjData;const Aname:string;allocflag:boolean);
 | 
						|
          procedure writeReloc_internal(aTarget:TObjSection;offset:aword;len:byte;reltype:TObjRelocationType);override;
 | 
						|
       end;
 | 
						|
 | 
						|
       TElfSymtabKind = (esk_obj,esk_exe,esk_dyn);
 | 
						|
 | 
						|
       TElfSymtab = class(TElfObjSection)
 | 
						|
       public
 | 
						|
         kind: TElfSymtabKind;
 | 
						|
         fstrsec: TObjSection;
 | 
						|
         symidx: longint;
 | 
						|
         tlsbase: aword;
 | 
						|
         constructor create(aObjData:TObjData;aKind:TElfSymtabKind);reintroduce;
 | 
						|
         procedure writeSymbol(objsym:TObjSymbol;nameidx:longword=0);
 | 
						|
         procedure writeInternalSymbol(avalue:aword;astridx:longword;ainfo:byte;ashndx:word);
 | 
						|
       end;
 | 
						|
 | 
						|
       TElfObjData = class(TObjData)
 | 
						|
       public
 | 
						|
         ident: TElfIdent;
 | 
						|
         flags: longword;
 | 
						|
{$ifdef mips}
 | 
						|
         gp_value: longword;
 | 
						|
{$endif mips}
 | 
						|
         constructor create(const n:string);override;
 | 
						|
         function  sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;override;
 | 
						|
         procedure CreateDebugSections;override;
 | 
						|
         procedure writereloc(data:aint;len:aword;p:TObjSymbol;reltype:TObjRelocationType);override;
 | 
						|
       end;
 | 
						|
 | 
						|
       TElfObjectOutput = class(tObjOutput)
 | 
						|
       private
 | 
						|
         symtabsect: TElfSymtab;
 | 
						|
         shstrtabsect: TElfObjSection;
 | 
						|
         procedure createrelocsection(s:TElfObjSection;data:TObjData);
 | 
						|
         procedure createshstrtab(data:TObjData);
 | 
						|
         procedure createsymtab(data: TObjData);
 | 
						|
         procedure writesectionheader(s:TElfObjSection);
 | 
						|
         procedure section_write_symbol(p:TObject;arg:pointer);
 | 
						|
         procedure section_count_sections(p:TObject;arg:pointer);
 | 
						|
         procedure section_create_relocsec(p:TObject;arg:pointer);
 | 
						|
         procedure section_write_sechdr(p:TObject;arg:pointer);
 | 
						|
       protected
 | 
						|
         function writedata(data:TObjData):boolean;override;
 | 
						|
       public
 | 
						|
         constructor Create(AWriter:TObjectWriter);override;
 | 
						|
       end;
 | 
						|
 | 
						|
       TElfAssembler = class(tinternalassembler)
 | 
						|
         constructor create(smart:boolean);override;
 | 
						|
       end;
 | 
						|
 | 
						|
       PSectionRec=^TSectionRec;
 | 
						|
       TSectionRec=record
 | 
						|
         sec: TObjSection;
 | 
						|
         relocpos: aword;
 | 
						|
         relocs: longint;
 | 
						|
         relentsize: longint;
 | 
						|
       end;
 | 
						|
 | 
						|
       TElfsecheaderarray=array of TElfsechdr;
 | 
						|
       TObjSymbolClass=class of TObjSymbol;
 | 
						|
 | 
						|
       TElfObjInput=class(TObjInput)
 | 
						|
       private
 | 
						|
         FSecTbl: PSectionRec;
 | 
						|
         FSymTbl: PPointer;
 | 
						|
         FLoaded: PBoolean;
 | 
						|
         shdrs: TElfsecheaderarray;
 | 
						|
         nsects: longword;
 | 
						|
         shoffset: aword;
 | 
						|
         shstrndx: longword;
 | 
						|
         symtabndx: longword;
 | 
						|
         shstrtab: PChar;
 | 
						|
         strtab: PChar;
 | 
						|
         shstrtablen: longword;
 | 
						|
         strtablen: longword;
 | 
						|
         symtaboffset: aword;
 | 
						|
         syms: longword;
 | 
						|
         localsyms: longword;
 | 
						|
         symversions: PWord;
 | 
						|
         dynobj: boolean;
 | 
						|
         CObjSymbol: TObjSymbolClass;
 | 
						|
         verdefs: TFPHashObjectList;
 | 
						|
         function LoadHeader(out objdata:TObjData):boolean;
 | 
						|
         procedure LoadSection(const shdr:TElfsechdr;index:longint;objdata:TObjData);
 | 
						|
         procedure LoadRelocations(const secrec:TSectionRec);
 | 
						|
         procedure LoadSymbols(objdata:TObjData;count,locals:longword);
 | 
						|
         procedure LoadDynamic(const shdr:TElfsechdr;objdata:TObjData);
 | 
						|
       public
 | 
						|
         constructor Create;override;
 | 
						|
         destructor Destroy;override;
 | 
						|
         function  ReadObjData(AReader:TObjectreader;out objdata:TObjData):boolean;override;
 | 
						|
         class function CanReadObjData(AReader:TObjectreader):boolean;override;
 | 
						|
         function CreateSection(const shdr:TElfsechdr;index:longint;objdata:TObjData;
 | 
						|
           out secname:string):TElfObjSection;
 | 
						|
         function ReadBytes(offs:longint;out buf;len:longint):boolean;
 | 
						|
       end;
 | 
						|
 | 
						|
       TElfVersionDef = class(TFPHashObject)
 | 
						|
       public
 | 
						|
         index: longword;
 | 
						|
       end;
 | 
						|
 | 
						|
       TElfDynamicObjData = class(TElfObjData)
 | 
						|
       private
 | 
						|
         FVersionDefs: TFPHashObjectList;
 | 
						|
       public
 | 
						|
         soname_strofs: longword;
 | 
						|
         vernaux_count: longword;
 | 
						|
         constructor create(const n:string);override;
 | 
						|
         destructor destroy;override;
 | 
						|
         property versiondefs:TFPHashObjectList read FVersionDefs;
 | 
						|
       end;
 | 
						|
 | 
						|
       TVersionedObjSymbol = class(TObjSymbol)
 | 
						|
       private
 | 
						|
         FVersion: TElfVersionDef;
 | 
						|
       public
 | 
						|
         property version: TElfVersionDef read FVersion write FVersion;
 | 
						|
       end;
 | 
						|
 | 
						|
       TRelocNameProc=function(reltyp:byte):string;
 | 
						|
       TEncodeRelocProc=function(objrel:TObjRelocation):byte;
 | 
						|
       TLoadRelocProc=procedure(objrel:TObjRelocation);
 | 
						|
       TLoadSectionProc=function(objinput:TElfObjInput;objdata:TObjData;const shdr:TElfsechdr;shindex:longint):boolean;
 | 
						|
       TDynamicReloc=(
 | 
						|
         dr_relative,
 | 
						|
         dr_glob_dat,
 | 
						|
         dr_jump_slot,
 | 
						|
         dr_copy,
 | 
						|
         dr_irelative
 | 
						|
       );
 | 
						|
 | 
						|
       TElfTarget=record
 | 
						|
         max_page_size: longword;
 | 
						|
         exe_image_base: longword;
 | 
						|
         machine_code: word;
 | 
						|
         relocs_use_addend: boolean;
 | 
						|
         dyn_reloc_codes: array[TDynamicReloc] of byte;
 | 
						|
         relocname: TRelocNameProc;
 | 
						|
         encodereloc: TEncodeRelocProc;
 | 
						|
         loadreloc: TLoadRelocProc;
 | 
						|
         loadsection: TLoadSectionProc;
 | 
						|
       end;
 | 
						|
 | 
						|
 | 
						|
       TElfExeSection=class(TExeSection)
 | 
						|
       public
 | 
						|
         secshidx  : longword; { index of the section header }
 | 
						|
         shstridx,
 | 
						|
         shtype,
 | 
						|
         shflags,
 | 
						|
         shlink,
 | 
						|
         shinfo,
 | 
						|
         shentsize : longword;
 | 
						|
         procedure AddObjSection(objsec:TObjSection;ignoreprops:boolean=false);override;
 | 
						|
       end;
 | 
						|
 | 
						|
       TElfSegment=class
 | 
						|
       public
 | 
						|
         ptype: longword;
 | 
						|
         pflags: longword;
 | 
						|
         DataPos: aword;
 | 
						|
         DataSize: aword;
 | 
						|
         MemPos: aword;
 | 
						|
         MemSize: aword;
 | 
						|
         align: longword;
 | 
						|
         //physaddr: aword;
 | 
						|
         FSectionList: TFPObjectList;
 | 
						|
         constructor Create(atype,aflags,aalign:longword);
 | 
						|
         destructor Destroy; override;
 | 
						|
         procedure Add(exesec:TExeSection);
 | 
						|
       end;
 | 
						|
 | 
						|
       TElfExeOutput=class(TExeOutput)
 | 
						|
       private
 | 
						|
         segmentlist: TFPObjectList;
 | 
						|
         textseg,
 | 
						|
         dataseg,
 | 
						|
         noteseg,
 | 
						|
         phdrseg: TElfSegment;
 | 
						|
         shstrtabsect: TElfObjSection;
 | 
						|
         symtab: TElfSymtab;
 | 
						|
         shoffset: aword;
 | 
						|
         gotwritten: boolean;
 | 
						|
         { dynamic linking }
 | 
						|
         dynsymnames: Plongword;
 | 
						|
         dynsymtable: TElfSymtab;
 | 
						|
         interpobjsec: TObjSection;
 | 
						|
         FInterpreter: pshortstring;
 | 
						|
         verneedcount,
 | 
						|
         verdefcount: longword;
 | 
						|
         symversec,
 | 
						|
         verdefsec,
 | 
						|
         verneedsec,
 | 
						|
         hashobjsec: TElfObjSection;
 | 
						|
         neededlist: TFPHashList;
 | 
						|
         dyncopysyms: TFPObjectList;
 | 
						|
 | 
						|
         function AttachSection(objsec:TObjSection):TElfExeSection;
 | 
						|
         function CreateSegment(atype,aflags,aalign:longword):TElfSegment;
 | 
						|
         procedure WriteHeader;
 | 
						|
         procedure WriteDynamicSymbolsHash;
 | 
						|
         procedure WriteVersionSections;
 | 
						|
         procedure WriteDynamicTags;
 | 
						|
         procedure FinishDynamicTags;
 | 
						|
         procedure exesection_write_header(p:TObject;arg:Pointer);
 | 
						|
         procedure segment_write_header(p:TObject;arg:Pointer);
 | 
						|
         procedure mempos_segment(seg:TElfSegment);
 | 
						|
         procedure datapos_segment(seg:TElfSegment);
 | 
						|
         procedure MapSectionsToSegments;
 | 
						|
         procedure WriteStaticSymtable;
 | 
						|
         procedure WriteShstrtab;
 | 
						|
         procedure FixupSectionLinks;
 | 
						|
         procedure InitDynlink;
 | 
						|
         procedure OrderOrphanSections;
 | 
						|
       protected
 | 
						|
         dynamiclink: boolean;
 | 
						|
         hastextrelocs: boolean;
 | 
						|
         gotsymbol: TObjSymbol;
 | 
						|
         dynsymlist: TFPObjectList;
 | 
						|
         dynamicsec,
 | 
						|
         gotobjsec: TObjSection;
 | 
						|
         dynbssobjsec,
 | 
						|
         pltobjsec,
 | 
						|
         gotpltobjsec,
 | 
						|
         pltrelocsec,
 | 
						|
         ipltrelocsec,
 | 
						|
         dynrelocsec: TElfObjSection;
 | 
						|
         dynreloclist: TFPObjectList;
 | 
						|
         tlsseg: TElfSegment;
 | 
						|
         relative_reloc_count: longint;
 | 
						|
         gotsize: aword;
 | 
						|
         dynrelsize: aword;
 | 
						|
         procedure PrepareGOT;virtual;
 | 
						|
         function AllocGOTSlot(objsym: TObjSymbol):boolean;virtual;
 | 
						|
         procedure CreateGOTSection;virtual;
 | 
						|
         procedure make_dynamic_if_undefweak(exesym:TExeSymbol);
 | 
						|
         procedure WriteDynRelocEntry(dataofs:aword;typ:byte;symidx:aword;addend:aword);
 | 
						|
         procedure CreatePLT;virtual;
 | 
						|
         procedure WriteFirstPLTEntry;virtual;abstract;
 | 
						|
         procedure WritePLTEntry(exesym:TExeSymbol);virtual;
 | 
						|
         procedure WriteIndirectPLTEntry(exesym:TExeSymbol);virtual;
 | 
						|
         procedure WriteTargetDynamicTags;virtual;
 | 
						|
         procedure GOTRelocPass1(objsec:TObjSection;var idx:longint);virtual;abstract;
 | 
						|
         procedure ReportNonDSOReloc(reltyp:byte;objsec:TObjSection;ObjReloc:TObjRelocation);
 | 
						|
         procedure ReportRelocOverflow(reltyp:byte;objsec:TObjSection;ObjReloc:TObjRelocation);
 | 
						|
         procedure WriteDynTag(aTag:longword;aValue:longword);
 | 
						|
         procedure WriteDynTag(aTag:longword;aSection:TObjSection;aOffs:aword=0);
 | 
						|
         procedure Do_Mempos;virtual;
 | 
						|
       public
 | 
						|
         constructor Create;override;
 | 
						|
         destructor Destroy;override;
 | 
						|
         procedure Load_Start;override;
 | 
						|
         procedure Load_DynamicObject(ObjData:TObjData;asneeded:boolean);override;
 | 
						|
         procedure Order_Start;override;
 | 
						|
         procedure Order_end;override;
 | 
						|
         procedure AfterUnusedSectionRemoval;override;
 | 
						|
         procedure MemPos_Start;override;
 | 
						|
         procedure MemPos_ExeSection(const aname:string);override;
 | 
						|
         procedure DataPos_Start;override;
 | 
						|
         procedure DataPos_ExeSection(const aname:string);override;
 | 
						|
         function writeData:boolean;override;
 | 
						|
         procedure GenerateLibraryImports(ImportLibraryList:TFPHashObjectList);override;
 | 
						|
         property interpreter:pshortstring read FInterpreter write FInterpreter;
 | 
						|
       end;
 | 
						|
 | 
						|
     var
 | 
						|
       ElfExeOutputClass: TExeOutputClass;
 | 
						|
       ElfTarget: TElfTarget;
 | 
						|
 | 
						|
     const
 | 
						|
       { Bits of TObjSymbol.refs field }
 | 
						|
       symref_plt = 1;
 | 
						|
       symref_from_text = 2;
 | 
						|
 | 
						|
 | 
						|
 | 
						|
implementation
 | 
						|
 | 
						|
      uses
 | 
						|
        SysUtils,
 | 
						|
        verbose,
 | 
						|
        export,expunix,
 | 
						|
        cutils,globals,fmodule;
 | 
						|
 | 
						|
    const
 | 
						|
      symbolresize = 200*18;
 | 
						|
 | 
						|
{$ifdef cpu64bitaddr}
 | 
						|
      const
 | 
						|
        ELFCLASS = ELFCLASS64;
 | 
						|
      type
 | 
						|
        telfheader = telf64header;
 | 
						|
        telfreloc = telf64reloc;
 | 
						|
        telfsymbol = telf64symbol;
 | 
						|
        telfproghdr = telf64proghdr;
 | 
						|
        telfdyn = telf64dyn;
 | 
						|
 | 
						|
      function ELF_R_INFO(sym:longword;typ:byte):qword;inline;
 | 
						|
        begin
 | 
						|
          result:=(qword(sym) shl 32) or typ;
 | 
						|
        end;
 | 
						|
 | 
						|
{$else cpu64bitaddr}
 | 
						|
      const
 | 
						|
        ELFCLASS = ELFCLASS32;
 | 
						|
      type
 | 
						|
        telfheader = telf32header;
 | 
						|
        telfreloc = telf32reloc;
 | 
						|
        telfsymbol = telf32symbol;
 | 
						|
        telfproghdr = telf32proghdr;
 | 
						|
        telfdyn = telf32dyn;
 | 
						|
 | 
						|
      function ELF_R_INFO(sym:longword;typ:byte):longword;inline;
 | 
						|
        begin
 | 
						|
          result:=(sym shl 8) or typ;
 | 
						|
        end;
 | 
						|
{$endif cpu64bitaddr}
 | 
						|
 | 
						|
      procedure MayBeSwapHeader(var h : telf32header);
 | 
						|
        begin
 | 
						|
          if source_info.endian<>target_info.endian then
 | 
						|
            with h do
 | 
						|
              begin
 | 
						|
                e_type:=swapendian(e_type);
 | 
						|
                e_machine:=swapendian(e_machine);
 | 
						|
                e_version:=swapendian(e_version);
 | 
						|
                e_entry:=swapendian(e_entry);
 | 
						|
                e_phoff:=swapendian(e_phoff);
 | 
						|
                e_shoff:=swapendian(e_shoff);
 | 
						|
                e_flags:=swapendian(e_flags);
 | 
						|
                e_ehsize:=swapendian(e_ehsize);
 | 
						|
                e_phentsize:=swapendian(e_phentsize);
 | 
						|
                e_phnum:=swapendian(e_phnum);
 | 
						|
                e_shentsize:=swapendian(e_shentsize);
 | 
						|
                e_shnum:=swapendian(e_shnum);
 | 
						|
                e_shstrndx:=swapendian(e_shstrndx);
 | 
						|
              end;
 | 
						|
        end;
 | 
						|
 | 
						|
 | 
						|
      procedure MayBeSwapHeader(var h : telf64header);
 | 
						|
        begin
 | 
						|
          if source_info.endian<>target_info.endian then
 | 
						|
            with h do
 | 
						|
              begin
 | 
						|
                e_type:=swapendian(e_type);
 | 
						|
                e_machine:=swapendian(e_machine);
 | 
						|
                e_version:=swapendian(e_version);
 | 
						|
                e_entry:=swapendian(e_entry);
 | 
						|
                e_phoff:=swapendian(e_phoff);
 | 
						|
                e_shoff:=swapendian(e_shoff);
 | 
						|
                e_flags:=swapendian(e_flags);
 | 
						|
                e_ehsize:=swapendian(e_ehsize);
 | 
						|
                e_phentsize:=swapendian(e_phentsize);
 | 
						|
                e_phnum:=swapendian(e_phnum);
 | 
						|
                e_shentsize:=swapendian(e_shentsize);
 | 
						|
                e_shnum:=swapendian(e_shnum);
 | 
						|
                e_shstrndx:=swapendian(e_shstrndx);
 | 
						|
              end;
 | 
						|
        end;
 | 
						|
 | 
						|
 | 
						|
      procedure MayBeSwapHeader(var h : telf32proghdr);
 | 
						|
        begin
 | 
						|
          if source_info.endian<>target_info.endian then
 | 
						|
            with h do
 | 
						|
              begin
 | 
						|
                p_align:=swapendian(p_align);
 | 
						|
                p_filesz:=swapendian(p_filesz);
 | 
						|
                p_flags:=swapendian(p_flags);
 | 
						|
                p_memsz:=swapendian(p_memsz);
 | 
						|
                p_offset:=swapendian(p_offset);
 | 
						|
                p_paddr:=swapendian(p_paddr);
 | 
						|
                p_type:=swapendian(p_type);
 | 
						|
                p_vaddr:=swapendian(p_vaddr);
 | 
						|
              end;
 | 
						|
        end;
 | 
						|
 | 
						|
 | 
						|
      procedure MayBeSwapHeader(var h : telf64proghdr);
 | 
						|
        begin
 | 
						|
          if source_info.endian<>target_info.endian then
 | 
						|
            with h do
 | 
						|
              begin
 | 
						|
                p_align:=swapendian(p_align);
 | 
						|
                p_filesz:=swapendian(p_filesz);
 | 
						|
                p_flags:=swapendian(p_flags);
 | 
						|
                p_memsz:=swapendian(p_memsz);
 | 
						|
                p_offset:=swapendian(p_offset);
 | 
						|
                p_paddr:=swapendian(p_paddr);
 | 
						|
                p_type:=swapendian(p_type);
 | 
						|
                p_vaddr:=swapendian(p_vaddr);
 | 
						|
              end;
 | 
						|
        end;
 | 
						|
 | 
						|
 | 
						|
      procedure MaybeSwapSecHeader(var h : telf32sechdr);
 | 
						|
        begin
 | 
						|
          if source_info.endian<>target_info.endian then
 | 
						|
            with h do
 | 
						|
              begin
 | 
						|
                sh_name:=swapendian(sh_name);
 | 
						|
                sh_type:=swapendian(sh_type);
 | 
						|
                sh_flags:=swapendian(sh_flags);
 | 
						|
                sh_addr:=swapendian(sh_addr);
 | 
						|
                sh_offset:=swapendian(sh_offset);
 | 
						|
                sh_size:=swapendian(sh_size);
 | 
						|
                sh_link:=swapendian(sh_link);
 | 
						|
                sh_info:=swapendian(sh_info);
 | 
						|
                sh_addralign:=swapendian(sh_addralign);
 | 
						|
                sh_entsize:=swapendian(sh_entsize);
 | 
						|
              end;
 | 
						|
        end;
 | 
						|
 | 
						|
 | 
						|
      procedure MaybeSwapSecHeader(var h : telf64sechdr);
 | 
						|
        begin
 | 
						|
          if source_info.endian<>target_info.endian then
 | 
						|
            with h do
 | 
						|
              begin
 | 
						|
                sh_name:=swapendian(sh_name);
 | 
						|
                sh_type:=swapendian(sh_type);
 | 
						|
                sh_flags:=swapendian(sh_flags);
 | 
						|
                sh_addr:=swapendian(sh_addr);
 | 
						|
                sh_offset:=swapendian(sh_offset);
 | 
						|
                sh_size:=swapendian(sh_size);
 | 
						|
                sh_link:=swapendian(sh_link);
 | 
						|
                sh_info:=swapendian(sh_info);
 | 
						|
                sh_addralign:=swapendian(sh_addralign);
 | 
						|
                sh_entsize:=swapendian(sh_entsize);
 | 
						|
              end;
 | 
						|
        end;
 | 
						|
 | 
						|
 | 
						|
      procedure MaybeSwapElfSymbol(var h : telf32symbol);
 | 
						|
        begin
 | 
						|
          if source_info.endian<>target_info.endian then
 | 
						|
            with h do
 | 
						|
              begin
 | 
						|
                st_name:=swapendian(st_name);
 | 
						|
                st_value:=swapendian(st_value);
 | 
						|
                st_size:=swapendian(st_size);
 | 
						|
                st_shndx:=swapendian(st_shndx);
 | 
						|
              end;
 | 
						|
        end;
 | 
						|
 | 
						|
 | 
						|
      procedure MaybeSwapElfSymbol(var h : telf64symbol);
 | 
						|
        begin
 | 
						|
          if source_info.endian<>target_info.endian then
 | 
						|
            with h do
 | 
						|
              begin
 | 
						|
                st_name:=swapendian(st_name);
 | 
						|
                st_value:=swapendian(st_value);
 | 
						|
                st_size:=swapendian(st_size);
 | 
						|
                st_shndx:=swapendian(st_shndx);
 | 
						|
              end;
 | 
						|
        end;
 | 
						|
 | 
						|
 | 
						|
      procedure MaybeSwapElfReloc(var h : telf32reloc);
 | 
						|
        begin
 | 
						|
          if source_info.endian<>target_info.endian then
 | 
						|
            with h do
 | 
						|
              begin
 | 
						|
                address:=swapendian(address);
 | 
						|
                info:=swapendian(info);
 | 
						|
                addend:=swapendian(addend);
 | 
						|
              end;
 | 
						|
        end;
 | 
						|
 | 
						|
 | 
						|
      procedure MaybeSwapElfReloc(var h : telf64reloc);
 | 
						|
        begin
 | 
						|
          if source_info.endian<>target_info.endian then
 | 
						|
            with h do
 | 
						|
              begin
 | 
						|
                address:=swapendian(address);
 | 
						|
                info:=swapendian(info);
 | 
						|
                addend:=swapendian(addend);
 | 
						|
              end;
 | 
						|
        end;
 | 
						|
 | 
						|
 | 
						|
      procedure MaybeSwapElfDyn(var h : telf32dyn);
 | 
						|
        begin
 | 
						|
          if source_info.endian<>target_info.endian then
 | 
						|
            with h do
 | 
						|
              begin
 | 
						|
                d_tag:=swapendian(d_tag);
 | 
						|
                d_val:=swapendian(d_val);
 | 
						|
              end;
 | 
						|
        end;
 | 
						|
 | 
						|
 | 
						|
      procedure MaybeSwapElfDyn(var h : telf64dyn);
 | 
						|
        begin
 | 
						|
          if source_info.endian<>target_info.endian then
 | 
						|
            with h do
 | 
						|
              begin
 | 
						|
                d_tag:=swapendian(d_tag);
 | 
						|
                d_val:=swapendian(d_val);
 | 
						|
              end;
 | 
						|
        end;
 | 
						|
 | 
						|
 | 
						|
      procedure MaybeSwapElfverdef(var h: TElfverdef);
 | 
						|
        begin
 | 
						|
          if source_info.endian<>target_info.endian then
 | 
						|
            with h do
 | 
						|
              begin
 | 
						|
                vd_version:=swapendian(vd_version);
 | 
						|
                vd_flags:=swapendian(vd_flags);
 | 
						|
                vd_ndx:=swapendian(vd_ndx);
 | 
						|
                vd_cnt:=swapendian(vd_cnt);
 | 
						|
                vd_hash:=swapendian(vd_hash);
 | 
						|
                vd_aux:=swapendian(vd_aux);
 | 
						|
                vd_next:=swapendian(vd_next);
 | 
						|
              end;
 | 
						|
        end;
 | 
						|
 | 
						|
 | 
						|
      procedure MaybeSwapElfverdaux(var h: TElfverdaux);
 | 
						|
        begin
 | 
						|
          if source_info.endian<>target_info.endian then
 | 
						|
            with h do
 | 
						|
              begin
 | 
						|
                vda_name:=swapendian(vda_name);
 | 
						|
                vda_next:=swapendian(vda_next);
 | 
						|
              end;
 | 
						|
        end;
 | 
						|
 | 
						|
 | 
						|
      procedure MaybeSwapElfverneed(var h: TElfverneed);
 | 
						|
        begin
 | 
						|
          if source_info.endian<>target_info.endian then
 | 
						|
            with h do
 | 
						|
              begin
 | 
						|
                vn_version:=swapendian(vn_version);
 | 
						|
                vn_cnt:=swapendian(vn_cnt);
 | 
						|
                vn_file:=swapendian(vn_file);
 | 
						|
                vn_aux:=swapendian(vn_aux);
 | 
						|
                vn_next:=swapendian(vn_next);
 | 
						|
              end;
 | 
						|
        end;
 | 
						|
 | 
						|
 | 
						|
      procedure MaybeSwapElfvernaux(var h: TElfvernaux);
 | 
						|
        begin
 | 
						|
          if source_info.endian<>target_info.endian then
 | 
						|
            with h do
 | 
						|
              begin
 | 
						|
                vna_hash:=swapendian(vna_hash);
 | 
						|
                vna_flags:=swapendian(vna_flags);
 | 
						|
                vna_other:=swapendian(vna_other);
 | 
						|
                vna_name:=swapendian(vna_name);
 | 
						|
                vna_next:=swapendian(vna_next);
 | 
						|
              end;
 | 
						|
        end;
 | 
						|
 | 
						|
 | 
						|
{****************************************************************************
 | 
						|
                                Helpers
 | 
						|
****************************************************************************}
 | 
						|
 | 
						|
    procedure encodesechdrflags(aoptions:TObjSectionOptions;out AshType:longint;out Ashflags:longint);
 | 
						|
      begin
 | 
						|
        { Section Type }
 | 
						|
        AshType:=SHT_PROGBITS;
 | 
						|
        if oso_strings in aoptions then
 | 
						|
          AshType:=SHT_STRTAB
 | 
						|
        else if not(oso_data in aoptions) then
 | 
						|
          AshType:=SHT_NOBITS;
 | 
						|
        { Section Flags }
 | 
						|
        Ashflags:=0;
 | 
						|
        if oso_load in aoptions then
 | 
						|
          Ashflags:=Ashflags or SHF_ALLOC;
 | 
						|
        if oso_executable in aoptions then
 | 
						|
          Ashflags:=Ashflags or SHF_EXECINSTR;
 | 
						|
        if oso_write in aoptions then
 | 
						|
          Ashflags:=Ashflags or SHF_WRITE;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure decodesechdrflags(AshType:longint;Ashflags:longint;out aoptions:TObjSectionOptions);
 | 
						|
      begin
 | 
						|
        aoptions:=[];
 | 
						|
        { Section Type }
 | 
						|
        if AshType<>SHT_NOBITS then
 | 
						|
          include(aoptions,oso_data);
 | 
						|
        if AshType=SHT_STRTAB then
 | 
						|
          include(aoptions,oso_strings);
 | 
						|
        { Section Flags }
 | 
						|
        if Ashflags and SHF_ALLOC<>0 then
 | 
						|
          include(aoptions,oso_load);
 | 
						|
        if Ashflags and SHF_WRITE<>0 then
 | 
						|
          include(aoptions,oso_write);
 | 
						|
        if Ashflags and SHF_EXECINSTR<>0 then
 | 
						|
          include(aoptions,oso_executable);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
{****************************************************************************
 | 
						|
                               TElfObjSection
 | 
						|
****************************************************************************}
 | 
						|
 | 
						|
    constructor TElfObjSection.create(AList:TFPHashObjectList;const Aname:string;Aalign:shortint;Aoptions:TObjSectionOptions);
 | 
						|
      begin
 | 
						|
        inherited create(AList,Aname,Aalign,aoptions);
 | 
						|
        index:=0;
 | 
						|
        shstridx:=0;
 | 
						|
        encodesechdrflags(aoptions,shtype,shflags);
 | 
						|
        shlink:=0;
 | 
						|
        shinfo:=0;
 | 
						|
        if name='.stab' then
 | 
						|
          shentsize:=sizeof(TObjStabEntry);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    constructor TElfObjSection.create_ext(aobjdata:TObjData;const Aname:string;Ashtype,Ashflags:longint;Aalign:shortint;Aentsize:longint);
 | 
						|
      var
 | 
						|
        aoptions : TObjSectionOptions;
 | 
						|
      begin
 | 
						|
        decodesechdrflags(Ashtype,Ashflags,aoptions);
 | 
						|
        inherited create(aobjdata.ObjSectionList,Aname,Aalign,aoptions);
 | 
						|
        objdata:=aobjdata;
 | 
						|
        index:=0;
 | 
						|
        shstridx:=0;
 | 
						|
        shtype:=AshType;
 | 
						|
        shflags:=AshFlags;
 | 
						|
        shentsize:=Aentsize;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    const
 | 
						|
      relsec_prefix:array[boolean] of string[5] = ('.rel','.rela');
 | 
						|
      relsec_shtype:array[boolean] of longword = (SHT_REL,SHT_RELA);
 | 
						|
 | 
						|
    constructor TElfObjSection.create_reloc(aobjdata:TObjData;const Aname:string;allocflag:boolean);
 | 
						|
      begin
 | 
						|
        create_ext(aobjdata,
 | 
						|
          relsec_prefix[ElfTarget.relocs_use_addend]+aname,
 | 
						|
          relsec_shtype[ElfTarget.relocs_use_addend],
 | 
						|
          SHF_ALLOC*ord(allocflag),
 | 
						|
          sizeof(pint),
 | 
						|
          (2+ord(ElfTarget.relocs_use_addend))*sizeof(pint));
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfObjSection.writeReloc_internal(aTarget:TObjSection;offset:aword;len:byte;reltype:TObjRelocationType);
 | 
						|
      var
 | 
						|
        reloc: TObjRelocation;
 | 
						|
      begin
 | 
						|
        reloc:=TObjRelocation.CreateSection(Size,aTarget,reltype);
 | 
						|
        reloc.size:=len;
 | 
						|
        ObjRelocations.Add(reloc);
 | 
						|
        if reltype=RELOC_RELATIVE then
 | 
						|
{ ARM does not require this adjustment, other CPUs must be checked }
 | 
						|
{$if defined(i386) or defined(x86_64)}
 | 
						|
          dec(offset,len)
 | 
						|
{$endif i386 or x86_64}
 | 
						|
        else if reltype<>RELOC_ABSOLUTE then
 | 
						|
          InternalError(2012062401);
 | 
						|
        if ElfTarget.relocs_use_addend then
 | 
						|
          begin
 | 
						|
            reloc.orgsize:=offset;
 | 
						|
            offset:=0;
 | 
						|
          end;
 | 
						|
        write(offset,len);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
{****************************************************************************
 | 
						|
                            TElfObjData
 | 
						|
****************************************************************************}
 | 
						|
 | 
						|
    constructor TElfObjData.create(const n:string);
 | 
						|
      begin
 | 
						|
        inherited create(n);
 | 
						|
        CObjSection:=TElfObjSection;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function TElfObjData.sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;
 | 
						|
      const
 | 
						|
        secnames : array[TAsmSectiontype] of string[length('__DATA, __datacoal_nt,coalesced')] = ('','',
 | 
						|
          { TODO: sec_rodata is still writable }
 | 
						|
          '.text','.data','.data','.rodata','.bss','.threadvar',
 | 
						|
          '.pdata',
 | 
						|
          '.text', { darwin stubs }
 | 
						|
          '__DATA,__nl_symbol_ptr',
 | 
						|
          '__DATA,__la_symbol_ptr',
 | 
						|
          '__DATA,__mod_init_func',
 | 
						|
          '__DATA,__mod_term_func',
 | 
						|
          '.stab','.stabstr',
 | 
						|
          '.idata$2','.idata$4','.idata$5','.idata$6','.idata$7','.edata',
 | 
						|
          '.eh_frame',
 | 
						|
          '.debug_frame','.debug_info','.debug_line','.debug_abbrev',
 | 
						|
          '.fpc',
 | 
						|
          '.toc',
 | 
						|
          '.init',
 | 
						|
          '.fini',
 | 
						|
          '.objc_class',
 | 
						|
          '.objc_meta_class',
 | 
						|
          '.objc_cat_cls_meth',
 | 
						|
          '.objc_cat_inst_meth',
 | 
						|
          '.objc_protocol',
 | 
						|
          '.objc_string_object',
 | 
						|
          '.objc_cls_meth',
 | 
						|
          '.objc_inst_meth',
 | 
						|
          '.objc_cls_refs',
 | 
						|
          '.objc_message_refs',
 | 
						|
          '.objc_symbols',
 | 
						|
          '.objc_category',
 | 
						|
          '.objc_class_vars',
 | 
						|
          '.objc_instance_vars',
 | 
						|
          '.objc_module_info',
 | 
						|
          '.objc_class_names',
 | 
						|
          '.objc_meth_var_types',
 | 
						|
          '.objc_meth_var_names',
 | 
						|
          '.objc_selector_strs',
 | 
						|
          '.objc_protocol_ext',
 | 
						|
          '.objc_class_ext',
 | 
						|
          '.objc_property',
 | 
						|
          '.objc_image_info',
 | 
						|
          '.objc_cstring_object',
 | 
						|
          '.objc_sel_fixup',
 | 
						|
          '__DATA,__objc_data',
 | 
						|
          '__DATA,__objc_const',
 | 
						|
          '.objc_superrefs',
 | 
						|
          '__DATA, __datacoal_nt,coalesced',
 | 
						|
          '.objc_classlist',
 | 
						|
          '.objc_nlclasslist',
 | 
						|
          '.objc_catlist',
 | 
						|
          '.obcj_nlcatlist',
 | 
						|
          '.objc_protolist'
 | 
						|
        );
 | 
						|
      var
 | 
						|
        sep : string[3];
 | 
						|
        secname : string;
 | 
						|
      begin
 | 
						|
        { section type user gives the user full controll on the section name }
 | 
						|
        if atype=sec_user then
 | 
						|
          result:=aname
 | 
						|
        else
 | 
						|
          begin
 | 
						|
            secname:=secnames[atype];
 | 
						|
            if (atype=sec_fpc) and (Copy(aname,1,3)='res') then
 | 
						|
              begin
 | 
						|
                result:=secname+'.'+aname;
 | 
						|
                exit;
 | 
						|
              end;
 | 
						|
            if create_smartlink_sections and (aname<>'') then
 | 
						|
              begin
 | 
						|
                case aorder of
 | 
						|
                  secorder_begin :
 | 
						|
                    sep:='.b_';
 | 
						|
                  secorder_end :
 | 
						|
                    sep:='.z_';
 | 
						|
                  else
 | 
						|
                    sep:='.n_';
 | 
						|
                end;
 | 
						|
                result:=secname+sep+aname
 | 
						|
              end
 | 
						|
            else
 | 
						|
              result:=secname;
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfObjData.CreateDebugSections;
 | 
						|
      begin
 | 
						|
        if target_dbg.id=dbg_stabs then
 | 
						|
          begin
 | 
						|
            stabssec:=createsection(sec_stab);
 | 
						|
            stabstrsec:=createsection(sec_stabstr);
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfObjData.writereloc(data:aint;len:aword;p:TObjSymbol;reltype:TObjRelocationType);
 | 
						|
      var
 | 
						|
        symaddr : aint;
 | 
						|
        objreloc: TObjRelocation;
 | 
						|
      begin
 | 
						|
        if CurrObjSec=nil then
 | 
						|
          internalerror(200403292);
 | 
						|
        objreloc:=nil;
 | 
						|
        if assigned(p) then
 | 
						|
         begin
 | 
						|
           { real address of the symbol }
 | 
						|
           symaddr:=p.address;
 | 
						|
           { Local ObjSymbols can be resolved already or need a section reloc }
 | 
						|
           if (p.bind=AB_LOCAL) and
 | 
						|
              (reltype in [RELOC_RELATIVE,RELOC_ABSOLUTE{$ifdef x86_64},RELOC_ABSOLUTE32{$endif x86_64}]) then
 | 
						|
             begin
 | 
						|
               { For a reltype relocation in the same section the
 | 
						|
                 value can be calculated }
 | 
						|
               if (p.objsection=CurrObjSec) and
 | 
						|
                  (reltype=RELOC_RELATIVE) then
 | 
						|
                 inc(data,symaddr-len-CurrObjSec.Size)
 | 
						|
               else
 | 
						|
                 begin
 | 
						|
                   objreloc:=TObjRelocation.CreateSection(CurrObjSec.Size,p.objsection,reltype);
 | 
						|
                   CurrObjSec.ObjRelocations.Add(objreloc);
 | 
						|
                   inc(data,symaddr);
 | 
						|
                 end;
 | 
						|
             end
 | 
						|
           else
 | 
						|
             begin
 | 
						|
               objreloc:=TObjRelocation.CreateSymbol(CurrObjSec.Size,p,reltype);
 | 
						|
               CurrObjSec.ObjRelocations.Add(objreloc);
 | 
						|
               { If target is a local label and it isn't handled above,
 | 
						|
                 patch its type in order to get it written to symtable.
 | 
						|
                 This may happen e.g. when taking address of Pascal label in PIC mode. }
 | 
						|
               if (p.bind=AB_LOCAL) and (p.typ=AT_LABEL) then
 | 
						|
                 p.typ:=AT_ADDR;
 | 
						|
            end;
 | 
						|
         end;
 | 
						|
        if assigned(objreloc) then
 | 
						|
          begin
 | 
						|
            objreloc.size:=len;
 | 
						|
            if reltype in [RELOC_RELATIVE{$ifdef x86},RELOC_PLT32{$endif}{$ifdef x86_64},RELOC_GOTPCREL{$endif}] then
 | 
						|
              dec(data,len);
 | 
						|
            if ElfTarget.relocs_use_addend then
 | 
						|
              begin
 | 
						|
                objreloc.orgsize:=aword(data);
 | 
						|
                data:=0;
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
        CurrObjSec.write(data,len);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
{****************************************************************************
 | 
						|
                            TElfDynamicObjData
 | 
						|
****************************************************************************}
 | 
						|
 | 
						|
    constructor TElfDynamicObjData.create(const n:string);
 | 
						|
      begin
 | 
						|
        inherited Create(n);
 | 
						|
        FVersionDefs:=TFPHashObjectList.create(true);
 | 
						|
        { Default symversions with indices 0 and 1 }
 | 
						|
        TElfVersionDef.create(FVersionDefs,'*local*');
 | 
						|
        TElfVersionDef.create(FVersionDefs,'*global*');
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    destructor TElfDynamicObjData.destroy;
 | 
						|
      begin
 | 
						|
        FVersionDefs.free;
 | 
						|
        inherited Destroy;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
{****************************************************************************
 | 
						|
                            TElfSymtab
 | 
						|
****************************************************************************}
 | 
						|
 | 
						|
    const
 | 
						|
      symsecnames: array[boolean] of string[8] = ('.symtab','.dynsym');
 | 
						|
      strsecnames: array[boolean] of string[8] = ('.strtab','.dynstr');
 | 
						|
      symsectypes: array[boolean] of longword  = (SHT_SYMTAB,SHT_DYNSYM);
 | 
						|
      symsecattrs: array[boolean] of longword  = (0,SHF_ALLOC);
 | 
						|
 | 
						|
 | 
						|
    constructor TElfSymtab.create(aObjData:TObjData;aKind:TElfSymtabKind);
 | 
						|
      var
 | 
						|
        dyn:boolean;
 | 
						|
      begin
 | 
						|
        dyn:=(aKind=esk_dyn);
 | 
						|
        create_ext(aObjData,symsecnames[dyn],symsectypes[dyn],symsecattrs[dyn],sizeof(pint),sizeof(TElfSymbol));
 | 
						|
        fstrsec:=TElfObjSection.create_ext(aObjData,strsecnames[dyn],SHT_STRTAB,symsecattrs[dyn],1,0);
 | 
						|
        fstrsec.writezeros(1);
 | 
						|
        writezeros(sizeof(TElfSymbol));
 | 
						|
        symidx:=1;
 | 
						|
        shinfo:=1;
 | 
						|
        kind:=aKind;
 | 
						|
      end;
 | 
						|
 | 
						|
    procedure TElfSymtab.writeInternalSymbol(avalue:aword;astridx:longword;ainfo:byte;ashndx:word);
 | 
						|
      var
 | 
						|
        elfsym:TElfSymbol;
 | 
						|
      begin
 | 
						|
        fillchar(elfsym,sizeof(elfsym),0);
 | 
						|
        elfsym.st_value:=avalue;
 | 
						|
        elfsym.st_name:=astridx;
 | 
						|
        elfsym.st_info:=ainfo;
 | 
						|
        elfsym.st_shndx:=ashndx;
 | 
						|
        inc(symidx);
 | 
						|
        inc(shinfo);
 | 
						|
        MaybeSwapElfSymbol(elfsym);
 | 
						|
        write(elfsym,sizeof(elfsym));
 | 
						|
      end;
 | 
						|
 | 
						|
    procedure TElfSymtab.writeSymbol(objsym:TObjSymbol;nameidx:longword);
 | 
						|
      var
 | 
						|
        elfsym:TElfSymbol;
 | 
						|
      begin
 | 
						|
        fillchar(elfsym,sizeof(elfsym),0);
 | 
						|
        if nameidx=0 then
 | 
						|
          elfsym.st_name:=fstrsec.writestr(objsym.name)
 | 
						|
        else
 | 
						|
          elfsym.st_name:=nameidx;
 | 
						|
        elfsym.st_size:=objsym.size;
 | 
						|
        elfsym.st_value:=objsym.address;
 | 
						|
        case objsym.bind of
 | 
						|
          AB_LOCAL :
 | 
						|
            begin
 | 
						|
              elfsym.st_info:=STB_LOCAL shl 4;
 | 
						|
              inc(shinfo);
 | 
						|
            end;
 | 
						|
          AB_COMMON :
 | 
						|
            begin
 | 
						|
              elfsym.st_value:=size_2_align(objsym.size);
 | 
						|
              elfsym.st_info:=STB_GLOBAL shl 4;
 | 
						|
              elfsym.st_shndx:=SHN_COMMON;
 | 
						|
            end;
 | 
						|
          AB_EXTERNAL :
 | 
						|
            elfsym.st_info:=STB_GLOBAL shl 4;
 | 
						|
          AB_WEAK_EXTERNAL :
 | 
						|
            elfsym.st_info:=STB_WEAK shl 4;
 | 
						|
          AB_GLOBAL :
 | 
						|
            elfsym.st_info:=STB_GLOBAL shl 4;
 | 
						|
        else
 | 
						|
          InternalError(2012111801);
 | 
						|
        end;
 | 
						|
        { External symbols must be NOTYPE in relocatable files }
 | 
						|
        if (objsym.bind<>AB_EXTERNAL) or (kind<>esk_obj) then
 | 
						|
          begin
 | 
						|
            case objsym.typ of
 | 
						|
              AT_FUNCTION :
 | 
						|
                elfsym.st_info:=elfsym.st_info or STT_FUNC;
 | 
						|
              AT_DATA :
 | 
						|
                elfsym.st_info:=elfsym.st_info or STT_OBJECT;
 | 
						|
              AT_TLS:
 | 
						|
                elfsym.st_info:=elfsym.st_info or STT_TLS;
 | 
						|
              AT_GNU_IFUNC:
 | 
						|
                elfsym.st_info:=elfsym.st_info or STT_GNU_IFUNC;
 | 
						|
            { other types are implicitly mapped to STT_NOTYPE }
 | 
						|
            end;
 | 
						|
          end;
 | 
						|
        if objsym.bind<>AB_COMMON then
 | 
						|
          begin
 | 
						|
            if kind<>esk_obj then
 | 
						|
              begin
 | 
						|
                if assigned(objsym.objsection) and assigned(objsym.objsection.ExeSection) then
 | 
						|
                  begin
 | 
						|
                    if (objsym.typ=AT_TLS) then
 | 
						|
                      elfsym.st_value:=elfsym.st_value-tlsbase
 | 
						|
                    else if (oso_plt in objsym.objsection.SecOptions) then
 | 
						|
                      elfsym.st_value:=0
 | 
						|
                    else
 | 
						|
                      elfsym.st_shndx:=TElfExeSection(objsym.objsection.ExeSection).secshidx;
 | 
						|
                  end;
 | 
						|
              end
 | 
						|
            else
 | 
						|
              begin
 | 
						|
                if assigned(objsym.objsection) then
 | 
						|
                  elfsym.st_shndx:=objsym.objsection.index
 | 
						|
                else
 | 
						|
                  elfsym.st_shndx:=SHN_UNDEF;
 | 
						|
                objsym.symidx:=symidx;
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
        inc(symidx);
 | 
						|
        MaybeSwapElfSymbol(elfsym);
 | 
						|
        write(elfsym,sizeof(TElfSymbol));
 | 
						|
      end;
 | 
						|
 | 
						|
{****************************************************************************
 | 
						|
                            TElfObjectOutput
 | 
						|
****************************************************************************}
 | 
						|
 | 
						|
    constructor TElfObjectOutput.create(AWriter:TObjectWriter);
 | 
						|
      begin
 | 
						|
        inherited Create(AWriter);
 | 
						|
        CObjData:=TElfObjData;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfObjectOutput.createrelocsection(s:TElfObjSection;data:TObjData);
 | 
						|
      var
 | 
						|
        i    : longint;
 | 
						|
        rel  : telfreloc;
 | 
						|
        objreloc : TObjRelocation;
 | 
						|
        relsym   : longint;
 | 
						|
        relocsect : TElfObjSection;
 | 
						|
      begin
 | 
						|
        { create the reloc section }
 | 
						|
        relocsect:=TElfObjSection.create_reloc(data,s.name,false);
 | 
						|
        relocsect.shlink:=symtabsect.index;
 | 
						|
        relocsect.shinfo:=s.index;
 | 
						|
        { add the relocations }
 | 
						|
        for i:=0 to s.Objrelocations.count-1 do
 | 
						|
          begin
 | 
						|
            objreloc:=TObjRelocation(s.Objrelocations[i]);
 | 
						|
 | 
						|
            { Symbol }
 | 
						|
            if assigned(objreloc.symbol) then
 | 
						|
              begin
 | 
						|
                if objreloc.symbol.symidx=-1 then
 | 
						|
                  begin
 | 
						|
                    writeln(objreloc.symbol.Name);
 | 
						|
                    internalerror(200603012);
 | 
						|
                  end;
 | 
						|
                relsym:=objreloc.symbol.symidx;
 | 
						|
              end
 | 
						|
            else
 | 
						|
              begin
 | 
						|
                if objreloc.objsection<>nil then
 | 
						|
                  relsym:=objreloc.objsection.secsymidx
 | 
						|
                else
 | 
						|
                  relsym:=SHN_UNDEF;
 | 
						|
              end;
 | 
						|
 | 
						|
            rel.address:=objreloc.dataoffset;
 | 
						|
            rel.info:=ELF_R_INFO(relsym,ElfTarget.encodereloc(objreloc));
 | 
						|
{$push}{$r-}
 | 
						|
            rel.addend:=objreloc.orgsize;
 | 
						|
{$pop}
 | 
						|
 | 
						|
            { write reloc }
 | 
						|
            { ElfXX_Rel is essentially ElfXX_Rela without the addend field. }
 | 
						|
            MaybeSwapElfReloc(rel);
 | 
						|
            relocsect.write(rel,relocsect.shentsize);
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfObjectOutput.section_write_symbol(p:TObject;arg:pointer);
 | 
						|
      begin
 | 
						|
        { Must not write symbols for internal sections like .symtab }
 | 
						|
        { TODO: maybe use inclusive list of section types instead }
 | 
						|
        if (TElfObjSection(p).shtype in [SHT_SYMTAB,SHT_STRTAB,SHT_REL,SHT_RELA]) then
 | 
						|
          exit;
 | 
						|
        TObjSection(p).secsymidx:=symtabsect.symidx;
 | 
						|
        symtabsect.writeInternalSymbol(0,0,STT_SECTION,TObjSection(p).index);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfObjectOutput.createsymtab(data: TObjData);
 | 
						|
      var
 | 
						|
        i      : longint;
 | 
						|
        objsym : TObjSymbol;
 | 
						|
      begin
 | 
						|
        with data do
 | 
						|
         begin
 | 
						|
           { section symbols }
 | 
						|
           ObjSectionList.ForEachCall(@section_write_symbol,nil);
 | 
						|
           { First the Local Symbols, this is required by ELF. The localsyms
 | 
						|
             count stored in shinfo is used to skip the local symbols
 | 
						|
             when traversing the symtab }
 | 
						|
           for i:=0 to ObjSymbolList.Count-1 do
 | 
						|
             begin
 | 
						|
               objsym:=TObjSymbol(ObjSymbolList[i]);
 | 
						|
               if (objsym.bind=AB_LOCAL) and (objsym.typ<>AT_LABEL) then
 | 
						|
                 symtabsect.WriteSymbol(objsym);
 | 
						|
             end;
 | 
						|
           { Global Symbols }
 | 
						|
           for i:=0 to ObjSymbolList.Count-1 do
 | 
						|
             begin
 | 
						|
               objsym:=TObjSymbol(ObjSymbolList[i]);
 | 
						|
               if (objsym.bind<>AB_LOCAL) then
 | 
						|
                 symtabsect.WriteSymbol(objsym);
 | 
						|
             end;
 | 
						|
           { update the .symtab section header }
 | 
						|
           symtabsect.shlink:=symtabsect.fstrsec.index;
 | 
						|
         end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfObjectOutput.createshstrtab(data: TObjData);
 | 
						|
      var
 | 
						|
        i,prefixlen:longint;
 | 
						|
        objsec,target:TElfObjSection;
 | 
						|
      begin
 | 
						|
        shstrtabsect.writezeros(1);
 | 
						|
        prefixlen:=length('.rel')+ord(ElfTarget.relocs_use_addend);
 | 
						|
        for i:=0 to data.ObjSectionList.Count-1 do
 | 
						|
          begin
 | 
						|
            objsec:=TElfObjSection(data.ObjSectionList[i]);
 | 
						|
            { Alias section names into names of corresponding reloc sections,
 | 
						|
              this is allowed by ELF specs and saves good half of .shstrtab space. }
 | 
						|
            if objsec.shtype=relsec_shtype[ElfTarget.relocs_use_addend] then
 | 
						|
              begin
 | 
						|
                target:=TElfObjSection(data.ObjSectionList[objsec.shinfo-1]);
 | 
						|
                if (target.ObjRelocations.Count=0) or
 | 
						|
                   (target.shstridx<prefixlen) then
 | 
						|
                  InternalError(2012101204);
 | 
						|
                objsec.shstridx:=target.shstridx-prefixlen;
 | 
						|
              end
 | 
						|
            else
 | 
						|
              begin
 | 
						|
                if objsec.ObjRelocations.Count<>0 then
 | 
						|
                  shstrtabsect.write(relsec_prefix[true][1],prefixlen);
 | 
						|
                objsec.shstridx:=shstrtabsect.writestr(objsec.name);
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfObjectOutput.writesectionheader(s:TElfObjSection);
 | 
						|
      var
 | 
						|
        sechdr : telfsechdr;
 | 
						|
      begin
 | 
						|
        fillchar(sechdr,sizeof(sechdr),0);
 | 
						|
        sechdr.sh_name:=s.shstridx;
 | 
						|
        sechdr.sh_type:=s.shtype;
 | 
						|
        sechdr.sh_flags:=s.shflags;
 | 
						|
        sechdr.sh_offset:=s.datapos;
 | 
						|
        sechdr.sh_size:=s.Size;
 | 
						|
        sechdr.sh_link:=s.shlink;
 | 
						|
        sechdr.sh_info:=s.shinfo;
 | 
						|
        sechdr.sh_addralign:=s.secalign;
 | 
						|
        sechdr.sh_entsize:=s.shentsize;
 | 
						|
        MaybeSwapSecHeader(sechdr);
 | 
						|
        writer.write(sechdr,sizeof(sechdr));
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfObjectOutput.section_count_sections(p:TObject;arg:pointer);
 | 
						|
      begin
 | 
						|
        TElfObjSection(p).index:=pword(arg)^;
 | 
						|
        inc(pword(arg)^);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfObjectOutput.section_create_relocsec(p:TObject;arg:pointer);
 | 
						|
      begin
 | 
						|
        if (TElfObjSection(p).ObjRelocations.count>0) then
 | 
						|
          createrelocsection(TElfObjSection(p),TObjData(arg));
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfObjectOutput.section_write_sechdr(p:TObject;arg:pointer);
 | 
						|
      begin
 | 
						|
        writesectionheader(TElfObjSection(p));
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function TElfObjectOutput.writedata(data:TObjData):boolean;
 | 
						|
      var
 | 
						|
        header : telfheader;
 | 
						|
        shoffset,
 | 
						|
        datapos   : aword;
 | 
						|
        nsections : word;
 | 
						|
      begin
 | 
						|
        result:=false;
 | 
						|
        with data do
 | 
						|
         begin
 | 
						|
           { default sections }
 | 
						|
           symtabsect:=TElfSymtab.create(data,esk_obj);
 | 
						|
           shstrtabsect:=TElfObjSection.create_ext(data,'.shstrtab',SHT_STRTAB,0,1,0);
 | 
						|
           { "no executable stack" marker for Linux }
 | 
						|
           if (target_info.system in (systems_linux + systems_android)) and
 | 
						|
              not(cs_executable_stack in current_settings.moduleswitches) then
 | 
						|
             TElfObjSection.create_ext(data,'.note.GNU-stack',SHT_PROGBITS,0,1,0);
 | 
						|
           { symbol for filename }
 | 
						|
           symtabsect.fstrsec.writestr(ExtractFileName(current_module.mainsource));
 | 
						|
           symtabsect.writeInternalSymbol(0,1,STT_FILE,SHN_ABS);
 | 
						|
           { calc amount of sections we have }
 | 
						|
           nsections:=1;
 | 
						|
           { also create the index in the section header table }
 | 
						|
           ObjSectionList.ForEachCall(@section_count_sections,@nsections);
 | 
						|
           { create .symtab and .strtab }
 | 
						|
           createsymtab(data);
 | 
						|
           { Create the relocation sections, this needs valid secidx and symidx }
 | 
						|
           ObjSectionList.ForEachCall(@section_create_relocsec,data);
 | 
						|
           { recalc nsections to incude the reloc sections }
 | 
						|
           nsections:=1;
 | 
						|
           ObjSectionList.ForEachCall(@section_count_sections,@nsections);
 | 
						|
           { create .shstrtab }
 | 
						|
           createshstrtab(data);
 | 
						|
 | 
						|
           { Calculate the filepositions }
 | 
						|
           datapos:=$40; { elfheader + alignment }
 | 
						|
           { section data }
 | 
						|
           layoutsections(datapos);
 | 
						|
           { section headers }
 | 
						|
           shoffset:=datapos;
 | 
						|
           inc(datapos,(nsections+1)*sizeof(telfsechdr));
 | 
						|
 | 
						|
           { Write ELF Header }
 | 
						|
           fillchar(header,sizeof(header),0);
 | 
						|
           header.e_ident[EI_MAG0]:=ELFMAG0; { = #127'ELF' }
 | 
						|
           header.e_ident[EI_MAG1]:=ELFMAG1;
 | 
						|
           header.e_ident[EI_MAG2]:=ELFMAG2;
 | 
						|
           header.e_ident[EI_MAG3]:=ELFMAG3;
 | 
						|
           header.e_ident[EI_CLASS]:=ELFCLASS;
 | 
						|
           if target_info.endian=endian_big then
 | 
						|
             header.e_ident[EI_DATA]:=ELFDATA2MSB
 | 
						|
           else
 | 
						|
             header.e_ident[EI_DATA]:=ELFDATA2LSB;
 | 
						|
 | 
						|
           header.e_ident[EI_VERSION]:=1;
 | 
						|
           if target_info.system in systems_openbsd then
 | 
						|
             header.e_ident[EI_OSABI]:=ELFOSABI_OPENBSD;
 | 
						|
           header.e_type:=ET_REL;
 | 
						|
           header.e_machine:=ElfTarget.machine_code;
 | 
						|
           header.e_version:=1;
 | 
						|
           header.e_shoff:=shoffset;
 | 
						|
           header.e_shstrndx:=shstrtabsect.index;
 | 
						|
 | 
						|
           header.e_shnum:=nsections;
 | 
						|
           header.e_ehsize:=sizeof(telfheader);
 | 
						|
           header.e_shentsize:=sizeof(telfsechdr);
 | 
						|
           MaybeSwapHeader(header);
 | 
						|
           writer.write(header,sizeof(header));
 | 
						|
           writer.writezeros($40-sizeof(header)); { align }
 | 
						|
           { Sections }
 | 
						|
           WriteSectionContent(data);
 | 
						|
           { section headers, start with an empty header for sh_undef }
 | 
						|
           writer.writezeros(sizeof(telfsechdr));
 | 
						|
           ObjSectionList.ForEachCall(@section_write_sechdr,nil);
 | 
						|
         end;
 | 
						|
        result:=true;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
{****************************************************************************
 | 
						|
                               TELFAssembler
 | 
						|
****************************************************************************}
 | 
						|
 | 
						|
    constructor TElfAssembler.Create(smart:boolean);
 | 
						|
      begin
 | 
						|
        inherited Create(smart);
 | 
						|
        CObjOutput:=TElfObjectOutput;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
{****************************************************************************
 | 
						|
                               TELFObjectInput
 | 
						|
****************************************************************************}
 | 
						|
 | 
						|
    constructor TElfObjInput.Create;
 | 
						|
      begin
 | 
						|
        inherited Create;
 | 
						|
        CObjData:=TElfObjData;
 | 
						|
        CObjSymbol:=TObjSymbol;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    destructor TElfObjInput.Destroy;
 | 
						|
      begin
 | 
						|
        if Assigned(FSymTbl) then
 | 
						|
          FreeMem(FSymTbl);
 | 
						|
        if Assigned(FSecTbl) then
 | 
						|
          FreeMem(FSecTbl);
 | 
						|
        if Assigned(strtab) then
 | 
						|
          FreeMem(strtab);
 | 
						|
        if Assigned(shstrtab) then
 | 
						|
          FreeMem(shstrtab);
 | 
						|
        if Assigned(symversions) then
 | 
						|
          FreeMem(symversions);
 | 
						|
        inherited Destroy;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfObjInput.LoadRelocations(const secrec:TSectionRec);
 | 
						|
      var
 | 
						|
        i: longint;
 | 
						|
        rel: TElfReloc;
 | 
						|
        reltyp: byte;
 | 
						|
        relsym: longint;
 | 
						|
        objrel: TObjRelocation;
 | 
						|
        p: TObjSymbol;
 | 
						|
      begin
 | 
						|
        FReader.Seek(secrec.relocpos);
 | 
						|
        if secrec.sec=nil then
 | 
						|
          InternalError(2012060203);
 | 
						|
        for i:=0 to secrec.relocs-1 do
 | 
						|
          begin
 | 
						|
            FReader.Read(rel,secrec.relentsize);
 | 
						|
            MaybeSwapElfReloc(rel);
 | 
						|
            reltyp:=rel.info and $FF;
 | 
						|
{$ifdef cpu64bitaddr}
 | 
						|
            relsym:=rel.info shr 32;
 | 
						|
{$else cpu64bitaddr}
 | 
						|
            relsym:=(rel.info shr 8) and $FFFFFF;
 | 
						|
{$endif cpu64bitaddr}
 | 
						|
            if relsym>=syms then
 | 
						|
              InternalError(2012060204);
 | 
						|
            p:=TObjSymbol(FSymTbl[relsym]);
 | 
						|
            { Some relocations (e.g. R_ARM_V4BX) don't use a symbol at all }
 | 
						|
            if assigned(p) or (relsym=0) then
 | 
						|
              begin
 | 
						|
                objrel:=TObjRelocation.CreateRaw(rel.address-secrec.sec.mempos,p,reltyp);
 | 
						|
                if (secrec.relentsize=3*sizeof(pint)) then
 | 
						|
                  objrel.orgsize:=rel.addend;
 | 
						|
                { perform target-specific actions }
 | 
						|
                if Assigned(ElfTarget.loadreloc) then
 | 
						|
                  ElfTarget.loadreloc(objrel);
 | 
						|
                secrec.sec.ObjRelocations.add(objrel);
 | 
						|
              end
 | 
						|
            else
 | 
						|
              begin
 | 
						|
                InputError('Unable to resolve symbol of relocation');
 | 
						|
                exit;
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfObjInput.LoadSymbols(objdata:TObjData;count,locals:longword);
 | 
						|
      var
 | 
						|
        i: longint;
 | 
						|
        sym: TElfSymbol;
 | 
						|
        bind: TAsmSymBind;
 | 
						|
        typ: TAsmSymType;
 | 
						|
        objsym: TObjSymbol;
 | 
						|
        ver: word;
 | 
						|
      begin
 | 
						|
        FSymTbl:=AllocMem(count*sizeof(Pointer));
 | 
						|
        for i:=1 to count-1 do
 | 
						|
          begin
 | 
						|
            FReader.Read(sym,sizeof(TElfSymbol));
 | 
						|
            MaybeSwapElfSymbol(sym);
 | 
						|
            if sym.st_name>=strtablen then
 | 
						|
              InternalError(2012060205);
 | 
						|
 | 
						|
            if sym.st_shndx=SHN_ABS then    { ignore absolute symbols (should we really do it???) }
 | 
						|
              Continue
 | 
						|
            else if sym.st_shndx=SHN_COMMON then
 | 
						|
              bind:=AB_COMMON
 | 
						|
            else if (sym.st_shndx>=nsects) then
 | 
						|
              InternalError(2012060206)
 | 
						|
            else
 | 
						|
              case (sym.st_info shr 4) of
 | 
						|
                STB_LOCAL:
 | 
						|
                  bind:=AB_LOCAL;
 | 
						|
                STB_GLOBAL:
 | 
						|
                  if sym.st_shndx=SHN_UNDEF then
 | 
						|
                    bind:=AB_EXTERNAL
 | 
						|
                  else
 | 
						|
                    bind:=AB_GLOBAL;
 | 
						|
                STB_WEAK:
 | 
						|
                  bind:=AB_WEAK_EXTERNAL;
 | 
						|
              else
 | 
						|
                InternalError(2012060207);
 | 
						|
              end;
 | 
						|
 | 
						|
            { Ignore section symbol if we didn't create the corresponding objsection
 | 
						|
              (examples are SHT_GROUP or .note.GNU-stack sections). }
 | 
						|
            if (sym.st_shndx>0) and (sym.st_shndx<SHN_LORESERVE) and
 | 
						|
              (FSecTbl[sym.st_shndx].sec=nil) and
 | 
						|
              (not dynobj) then
 | 
						|
              if ((sym.st_info and $0F)=STT_SECTION) then
 | 
						|
                Continue
 | 
						|
              else
 | 
						|
                begin
 | 
						|
                  writeln(objdata.name,' ',i);
 | 
						|
                  InternalError(2012110701)
 | 
						|
                end;
 | 
						|
 | 
						|
            case (sym.st_info and $0F) of
 | 
						|
              STT_NOTYPE:
 | 
						|
                typ:=AT_NONE;
 | 
						|
              STT_OBJECT:
 | 
						|
                typ:=AT_DATA;
 | 
						|
              STT_FUNC:
 | 
						|
                typ:=AT_FUNCTION;
 | 
						|
              STT_SECTION:
 | 
						|
                typ:=AT_SECTION;
 | 
						|
              STT_FILE:
 | 
						|
                continue;
 | 
						|
              STT_TLS:
 | 
						|
                typ:=AT_TLS;
 | 
						|
              STT_GNU_IFUNC:
 | 
						|
                typ:=AT_GNU_IFUNC;
 | 
						|
            else
 | 
						|
              writeln(objdata.name,' ',sym.st_info and $0F);
 | 
						|
              InternalError(2012060208);
 | 
						|
            end;
 | 
						|
            { If reading DSO, we're interested only in global symbols defined there.
 | 
						|
              Symbols with non-current version should also be ignored. }
 | 
						|
            ver:=0;
 | 
						|
            if dynobj then
 | 
						|
              begin
 | 
						|
                if assigned(symversions) then
 | 
						|
                  begin
 | 
						|
                    ver:=symversions[i];
 | 
						|
                    if (ver=VER_NDX_LOCAL) or (ver>VERSYM_VERSION) then
 | 
						|
                      continue;
 | 
						|
                  end;
 | 
						|
                if (bind=AB_LOCAL) or (sym.st_shndx=SHN_UNDEF) then
 | 
						|
                  continue;
 | 
						|
                if ver>=verdefs.count then
 | 
						|
                  InternalError(2012120505);
 | 
						|
              end;
 | 
						|
            { validity of name and objsection has been checked above }
 | 
						|
            { !! all AT_SECTION symbols have duplicate (null) name,
 | 
						|
              therefore TObjSection.CreateSymbol cannot be used here }
 | 
						|
            objsym:=CObjSymbol.Create(objdata.ObjSymbolList,string(PChar(@strtab[sym.st_name])));
 | 
						|
            objsym.bind:=bind;
 | 
						|
            objsym.typ:=typ;
 | 
						|
            if bind<>AB_COMMON then
 | 
						|
              objsym.objsection:=FSecTbl[sym.st_shndx].sec;
 | 
						|
            objsym.offset:=sym.st_value;
 | 
						|
            objsym.size:=sym.st_size;
 | 
						|
            FSymTbl[i]:=objsym;
 | 
						|
            if (ver>VER_NDX_GLOBAL) then
 | 
						|
              TVersionedObjSymbol(objsym).version:=TElfVersionDef(verdefs[ver]);
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function TElfObjInput.CreateSection(const shdr:TElfsechdr;index:longint;objdata:tobjdata;
 | 
						|
        out secname:string):TElfObjSection;
 | 
						|
      begin
 | 
						|
        secname:=string(PChar(@shstrtab[shdr.sh_name]));
 | 
						|
 | 
						|
        result:=TElfObjSection.create_ext(objdata,secname,
 | 
						|
          shdr.sh_type,shdr.sh_flags,shdr.sh_addralign,shdr.sh_entsize);
 | 
						|
 | 
						|
        result.index:=index;
 | 
						|
        result.DataPos:=shdr.sh_offset;
 | 
						|
        result.MemPos:=shdr.sh_addr;
 | 
						|
        result.Size:=shdr.sh_size;
 | 
						|
        FSecTbl[index].sec:=result;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function TElfObjInput.ReadBytes(offs:longint;out buf;len:longint):boolean;
 | 
						|
      begin
 | 
						|
        FReader.Seek(offs);
 | 
						|
        result:=FReader.Read(buf,len);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfObjInput.LoadSection(const shdr:TElfsechdr;index:longint;objdata:tobjdata);
 | 
						|
      var
 | 
						|
        sec: TElfObjSection;
 | 
						|
        sym: TElfSymbol;
 | 
						|
        secname: string;
 | 
						|
      begin
 | 
						|
        if shdr.sh_name>=shstrtablen then
 | 
						|
          InternalError(2012060210);
 | 
						|
 | 
						|
        case shdr.sh_type of
 | 
						|
          SHT_NULL:
 | 
						|
            {ignore};
 | 
						|
 | 
						|
          { SHT_STRTAB may appear for .stabstr and other debug sections.
 | 
						|
            .shstrtab and .strtab are processed separately and don't appear here. }
 | 
						|
          SHT_PROGBITS,SHT_NOBITS,SHT_NOTE,SHT_STRTAB,
 | 
						|
          SHT_INIT_ARRAY,SHT_FINI_ARRAY,SHT_PREINIT_ARRAY:
 | 
						|
            begin
 | 
						|
              sec:=CreateSection(shdr,index,objdata,secname);
 | 
						|
 | 
						|
              if (Length(secname)>3) and (secname[2] in ['d','f','n','s']) then
 | 
						|
                begin
 | 
						|
                  if (Pos('.stub',secname)=1) or
 | 
						|
                    (Pos('.fpc',secname)=1) then
 | 
						|
                    sec.SecOptions:=[oso_keep]
 | 
						|
                  { ELF does not have any flags specific to debug sections,
 | 
						|
                    but reserves names starting with '.debug' for this purpose }
 | 
						|
                  else if (Pos('.debug',secname)=1) or
 | 
						|
                    (secname='.stab') or
 | 
						|
                    (secname='.stabstr') then
 | 
						|
                    sec.SecOptions:=[oso_debug]
 | 
						|
                  else if (secname='.note.GNU-stack') and (shdr.sh_type=SHT_PROGBITS) then
 | 
						|
                    begin
 | 
						|
                      if (shdr.sh_flags and SHF_EXECINSTR)=0 then
 | 
						|
                        objdata.ExecStack:=False;
 | 
						|
                    end;
 | 
						|
                end;
 | 
						|
 | 
						|
              if (shdr.sh_type=SHT_NOTE) and (shdr.sh_size<>0) then
 | 
						|
                sec.SecOptions:=[oso_keep];
 | 
						|
            end;
 | 
						|
 | 
						|
          SHT_REL,SHT_RELA:
 | 
						|
            begin
 | 
						|
              if shdr.sh_info>=nsects then
 | 
						|
                InternalError(2012060211);
 | 
						|
              if shdr.sh_entsize<>longword((2+ord(shdr.sh_type=SHT_RELA))*sizeof(pint)) then
 | 
						|
                InternalError(2012060212);
 | 
						|
 | 
						|
              with FSecTbl[shdr.sh_info] do
 | 
						|
                begin
 | 
						|
                  relocpos:=shdr.sh_offset;
 | 
						|
                  relocs:=shdr.sh_size div shdr.sh_entsize;
 | 
						|
                  relentsize:=shdr.sh_entsize;
 | 
						|
                end;
 | 
						|
            end;
 | 
						|
 | 
						|
          SHT_GROUP:
 | 
						|
            if (shdr.sh_size>=2*sizeof(longword)) and
 | 
						|
              (shdr.sh_entsize=sizeof(longword)) and
 | 
						|
              ((shdr.sh_size mod shdr.sh_entsize)=0) then
 | 
						|
              begin
 | 
						|
                { Groups are identified by name of symbol pointed to by
 | 
						|
                  sh_link and sh_info, not by sh_name. This symbol
 | 
						|
                  may as well be STT_SECTION symbol of this section,
 | 
						|
                  in which case we end up using sh_name. }
 | 
						|
                if dynobj then
 | 
						|
                  InternalError(2012110801);
 | 
						|
                if (shdr.sh_link<>symtabndx) then
 | 
						|
                  InternalError(2012110703);
 | 
						|
                if (shdr.sh_info>=syms) then
 | 
						|
                  InternalError(2012110704);
 | 
						|
 | 
						|
                FReader.Seek(symtaboffset+shdr.sh_info*sizeof(TElfSymbol));
 | 
						|
                FReader.Read(sym,sizeof(TElfSymbol));
 | 
						|
                MaybeSwapElfSymbol(sym);
 | 
						|
                if sym.st_name>=strtablen then
 | 
						|
                  InternalError(2012110705);
 | 
						|
                if (sym.st_shndx=index) and (sym.st_info=((STB_LOCAL shl 4) or STT_SECTION)) then
 | 
						|
                  secname:=string(PChar(@shstrtab[shdr.sh_name]))
 | 
						|
                else
 | 
						|
                  secname:=string(PChar(@strtab[sym.st_name]));
 | 
						|
 | 
						|
                { Postpone further processing until all sections are loaded,
 | 
						|
                  we'll need to access correct section header.
 | 
						|
                  Since ABI requires SHT_GROUP sections to come first in the file,
 | 
						|
                  we assume that group number x has header index x+1.
 | 
						|
                  If we ever encounter files where this is not true, we'll have
 | 
						|
                  to maintain a separate index. }
 | 
						|
                objdata.CreateSectionGroup(secname);
 | 
						|
                if (index<>objdata.GroupsList.Count) then
 | 
						|
                  InternalError(2012110802);
 | 
						|
              end
 | 
						|
            else
 | 
						|
              InternalError(2012110706);
 | 
						|
 | 
						|
          SHT_GNU_ATTRIBUTES:
 | 
						|
            { TODO: must not be ignored };
 | 
						|
        else
 | 
						|
          if not (assigned(ElfTarget.loadsection) and
 | 
						|
            ElfTarget.loadsection(self,objdata,shdr,index)) then
 | 
						|
            InternalError(2012072603);
 | 
						|
        end;
 | 
						|
        FLoaded[index]:=True;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function TElfObjInput.LoadHeader(out objdata:TObjData):boolean;
 | 
						|
      var
 | 
						|
        header:TElfHeader;
 | 
						|
      begin
 | 
						|
        result:=false;
 | 
						|
        if not FReader.read(header,sizeof(header)) then
 | 
						|
          begin
 | 
						|
            InputError('Can''t read ELF header');
 | 
						|
            exit;
 | 
						|
          end;
 | 
						|
        if (header.e_ident[EI_MAG0]<>ELFMAG0) or (header.e_ident[EI_MAG1]<>ELFMAG1) or
 | 
						|
           (header.e_ident[EI_MAG2]<>ELFMAG2) or (header.e_ident[EI_MAG3]<>ELFMAG3) then
 | 
						|
          begin
 | 
						|
            InputError('Illegal ELF magic');
 | 
						|
            exit;
 | 
						|
          end;
 | 
						|
        if (header.e_ident[EI_VERSION]<>1) then
 | 
						|
          begin
 | 
						|
            InputError('Unknown ELF file version');
 | 
						|
            exit;
 | 
						|
          end;
 | 
						|
        if (header.e_ident[EI_CLASS]<>ELFCLASS) then
 | 
						|
          begin
 | 
						|
            InputError('Wrong ELF file class (32/64 bit mismatch)');
 | 
						|
            exit;
 | 
						|
          end;
 | 
						|
        if (header.e_ident[EI_DATA]<>1+ord(target_info.endian=endian_big)) then
 | 
						|
          begin
 | 
						|
            InputError('ELF endianness does not match target');
 | 
						|
            exit;
 | 
						|
          end;
 | 
						|
        MaybeSwapHeader(header);
 | 
						|
        if (header.e_version<>1) then
 | 
						|
          begin
 | 
						|
            InputError('Unknown ELF data version');
 | 
						|
            exit;
 | 
						|
          end;
 | 
						|
        if (header.e_machine<>ElfTarget.machine_code) then
 | 
						|
          begin
 | 
						|
            InputError('ELF file is for different CPU');
 | 
						|
            exit;
 | 
						|
          end;
 | 
						|
        if (header.e_type<>ET_REL) and (header.e_type<>ET_DYN) then
 | 
						|
          begin
 | 
						|
            InputError('Not a relocatable or dynamic ELF file');
 | 
						|
            exit;
 | 
						|
          end;
 | 
						|
        if header.e_shentsize<>sizeof(TElfsechdr) then
 | 
						|
          InternalError(2012062701);
 | 
						|
 | 
						|
        nsects:=header.e_shnum;
 | 
						|
        dynobj:=(header.e_type=ET_DYN);
 | 
						|
        shoffset:=header.e_shoff;
 | 
						|
        shstrndx:=header.e_shstrndx;
 | 
						|
 | 
						|
        if dynobj then
 | 
						|
          begin
 | 
						|
            objdata:=TElfDynamicObjData.Create(InputFilename);
 | 
						|
            verdefs:=TElfDynamicObjData(objdata).versiondefs;
 | 
						|
            CObjSymbol:=TVersionedObjSymbol;
 | 
						|
          end
 | 
						|
        else
 | 
						|
          objdata:=CObjData.Create(InputFilename);
 | 
						|
 | 
						|
        TElfObjData(objdata).ident:=header.e_ident;
 | 
						|
        TElfObjData(objdata).flags:=header.e_flags;
 | 
						|
        result:=true;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfObjInput.LoadDynamic(const shdr:TElfsechdr;objdata:TObjData);
 | 
						|
      var
 | 
						|
        dt: TElfDyn;
 | 
						|
        i: longint;
 | 
						|
      begin
 | 
						|
        if (shdr.sh_entsize<>sizeof(TElfDyn)) then
 | 
						|
          InternalError(2012071403);
 | 
						|
 | 
						|
        FReader.Seek(shdr.sh_offset);
 | 
						|
        for i:=0 to (shdr.sh_size div shdr.sh_entsize)-1 do
 | 
						|
          begin
 | 
						|
            FReader.Read(dt,sizeof(TElfDyn));
 | 
						|
            MaybeSwapElfDyn(dt);
 | 
						|
            case dt.d_tag of
 | 
						|
              DT_NULL:
 | 
						|
                break;
 | 
						|
              DT_SONAME:
 | 
						|
                TElfObjData(objdata).FName:=string(PChar(@strtab[dt.d_ptr]));
 | 
						|
              DT_NEEDED:
 | 
						|
                ;
 | 
						|
            end;
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function TElfObjInput.ReadObjData(AReader:TObjectreader;out objdata:TObjData):boolean;
 | 
						|
      var
 | 
						|
        i,j,strndx,dynndx,
 | 
						|
        versymndx,verdefndx,verneedndx: longint;
 | 
						|
        objsec: TObjSection;
 | 
						|
        grp: TObjSectionGroup;
 | 
						|
        tmp: longword;
 | 
						|
        count: longint;
 | 
						|
        vd: TElfverdef;
 | 
						|
        vda: TElfverdaux;
 | 
						|
        vdoffset: aword;
 | 
						|
      begin
 | 
						|
        FReader:=AReader;
 | 
						|
        InputFileName:=AReader.FileName;
 | 
						|
        result:=false;
 | 
						|
        strndx:=0;
 | 
						|
 | 
						|
        if not LoadHeader(objData) then
 | 
						|
          exit;
 | 
						|
 | 
						|
        FSecTbl:=AllocMem(nsects*sizeof(TSectionRec));
 | 
						|
        FLoaded:=AllocMem(nsects*sizeof(boolean));
 | 
						|
        SetLength(shdrs,nsects);
 | 
						|
 | 
						|
        FReader.Seek(shoffset);
 | 
						|
        if not FReader.Read(shdrs[0],nsects*sizeof(TElfsechdr)) then
 | 
						|
          begin
 | 
						|
            InputError('Can''t read ELF section headers');
 | 
						|
            exit;
 | 
						|
          end;
 | 
						|
        if source_info.endian<>target_info.endian then
 | 
						|
          for i:=0 to nsects-1 do
 | 
						|
            MaybeSwapSecHeader(shdrs[i]);
 | 
						|
 | 
						|
        { First, load the .shstrtab section }
 | 
						|
        if shstrndx>=nsects then
 | 
						|
          InternalError(2012060201);
 | 
						|
        if shdrs[shstrndx].sh_type<>SHT_STRTAB then
 | 
						|
          InternalError(2012060202);
 | 
						|
        shstrtablen:=shdrs[shstrndx].sh_size;
 | 
						|
        GetMem(shstrtab,shstrtablen);
 | 
						|
        FReader.seek(shdrs[shstrndx].sh_offset);
 | 
						|
        FReader.read(shstrtab^,shstrtablen);
 | 
						|
        FLoaded[shstrndx]:=True;
 | 
						|
 | 
						|
        { Locate the symtable, it is typically at the end so loop backwards.
 | 
						|
          Load the strings, postpone symtable itself until done with sections.
 | 
						|
          Note that is is legal to have no symtable.
 | 
						|
          For DSO, locate .dynsym instead, this one is near the beginning, but
 | 
						|
          overall number of sections won't be big. }
 | 
						|
        symtabndx:=0;
 | 
						|
        for i:=nsects-1 downto 1 do
 | 
						|
          begin
 | 
						|
            if (shdrs[i].sh_type<>symsectypes[dynobj]) then
 | 
						|
              continue;
 | 
						|
            if (shdrs[i].sh_entsize<>sizeof(TElfSymbol)) then
 | 
						|
              InternalError(2012060213);
 | 
						|
            if shdrs[i].sh_link>=nsects then
 | 
						|
              InternalError(2012062702);
 | 
						|
            strndx:=shdrs[i].sh_link;
 | 
						|
            if shdrs[strndx].sh_type<>SHT_STRTAB then
 | 
						|
              InternalError(2012062703);
 | 
						|
            strtablen:=shdrs[strndx].sh_size;
 | 
						|
            GetMem(strtab,strtablen);
 | 
						|
            FReader.seek(shdrs[strndx].sh_offset);
 | 
						|
            FReader.read(strtab^,strtablen);
 | 
						|
 | 
						|
            symtaboffset:=shdrs[i].sh_offset;
 | 
						|
            syms:=shdrs[i].sh_size div sizeof(TElfSymbol);
 | 
						|
            localsyms:=shdrs[i].sh_info;
 | 
						|
            FLoaded[i]:=True;
 | 
						|
            FLoaded[strndx]:=True;
 | 
						|
            symtabndx:=i;
 | 
						|
            break;
 | 
						|
          end;
 | 
						|
 | 
						|
        if dynobj then
 | 
						|
          begin
 | 
						|
            if symtabndx=0 then
 | 
						|
              InternalError(2012110707);
 | 
						|
            { Locate .dynamic and version sections. Expect a single one of a kind. }
 | 
						|
            dynndx:=0;
 | 
						|
            versymndx:=0;
 | 
						|
            verdefndx:=0;
 | 
						|
            verneedndx:=0;
 | 
						|
            for i:=nsects-1 downto 0 do
 | 
						|
              begin
 | 
						|
                case shdrs[i].sh_type of
 | 
						|
                  SHT_DYNAMIC:
 | 
						|
                    begin
 | 
						|
                      if dynndx<>0 then
 | 
						|
                        InternalError(2012102001);
 | 
						|
                      dynndx:=i;
 | 
						|
                      if (shdrs[dynndx].sh_link<>strndx) then
 | 
						|
                        InternalError(2012071402);
 | 
						|
                      LoadDynamic(shdrs[dynndx],objdata);
 | 
						|
                    end;
 | 
						|
 | 
						|
                  SHT_GNU_versym:
 | 
						|
                    begin
 | 
						|
                      if versymndx<>0 then
 | 
						|
                        InternalError(2012102002);
 | 
						|
                      versymndx:=i;
 | 
						|
                      if shdrs[i].sh_entsize<>sizeof(word) then
 | 
						|
                        InternalError(2012102003);
 | 
						|
                      if shdrs[i].sh_link<>symtabndx then
 | 
						|
                        InternalError(2012102004);
 | 
						|
                      if shdrs[i].sh_size<>syms*sizeof(word) then
 | 
						|
                        InternalError(2012102005);
 | 
						|
                      GetMem(symversions,shdrs[i].sh_size);
 | 
						|
                      FReader.seek(shdrs[i].sh_offset);
 | 
						|
                      FReader.read(symversions^,shdrs[i].sh_size);
 | 
						|
                      if source_info.endian<>target_info.endian then
 | 
						|
                        for j:=0 to syms-1 do
 | 
						|
                          symversions[j]:=SwapEndian(symversions[j]);
 | 
						|
                    end;
 | 
						|
 | 
						|
                  SHT_GNU_verdef:
 | 
						|
                    begin
 | 
						|
                      if verdefndx<>0 then
 | 
						|
                        InternalError(2012102006);
 | 
						|
                      verdefndx:=i;
 | 
						|
                      if shdrs[i].sh_link<>strndx then
 | 
						|
                        InternalError(2012120501);
 | 
						|
                      vdoffset:=shdrs[i].sh_offset;
 | 
						|
                      { TODO: can we rely on sh_info, or must read until vd_next=0? }
 | 
						|
                      for j:=1 to shdrs[i].sh_info do
 | 
						|
                        begin
 | 
						|
                          FReader.seek(vdoffset);
 | 
						|
                          FReader.Read(vd,sizeof(TElfverdef));
 | 
						|
                          MaybeSwapElfverdef(vd);
 | 
						|
                          if vd.vd_version<>VER_DEF_CURRENT then
 | 
						|
                            InternalError(2012120502);
 | 
						|
                          FReader.seek(vdoffset+vd.vd_aux);
 | 
						|
                          vdoffset:=vdoffset+vd.vd_next;
 | 
						|
                          { First verdaux entry holds name of version (unless VER_FLG_BASE flag is set),
 | 
						|
                            subsequent one(s) point to parent(s). For our purposes, version hierarchy
 | 
						|
                            looks irrelevant. }
 | 
						|
                          FReader.Read(vda,sizeof(TElfverdaux));
 | 
						|
                          MaybeSwapElfverdaux(vda);
 | 
						|
                          if vda.vda_name>=strtablen then
 | 
						|
                            InternalError(2012120503);
 | 
						|
                          if (vd.vd_flags and VER_FLG_BASE)<>0 then
 | 
						|
                            continue;
 | 
						|
                          { Assuming verdef indices assigned continuously starting from 2,
 | 
						|
                            at least BFD produces files that way. }
 | 
						|
                          if verdefs.count<>vd.vd_ndx then
 | 
						|
                            InternalError(2012120504);
 | 
						|
                          TElfVersionDef.Create(verdefs,string(PChar(@strtab[vda.vda_name])));
 | 
						|
                        end;
 | 
						|
                    end;
 | 
						|
 | 
						|
                  SHT_GNU_verneed:
 | 
						|
                    begin
 | 
						|
                      if verneedndx<>0 then
 | 
						|
                        InternalError(2012102007);
 | 
						|
                      verneedndx:=i;
 | 
						|
                      //sh_link->.dynstr
 | 
						|
                      //sh_info->number of entries
 | 
						|
                    end;
 | 
						|
                end;
 | 
						|
             end;
 | 
						|
 | 
						|
            if dynndx=0 then
 | 
						|
              InternalError(2012071401);
 | 
						|
 | 
						|
            { load the symtable }
 | 
						|
            FReader.Seek(symtaboffset+sizeof(TElfSymbol));
 | 
						|
            LoadSymbols(objdata,syms,localsyms);
 | 
						|
 | 
						|
            result:=True;
 | 
						|
            exit;
 | 
						|
          end;
 | 
						|
 | 
						|
        { assume stack is executable until proven otherwise }
 | 
						|
        objdata.ExecStack:=True;
 | 
						|
 | 
						|
        { Process section headers }
 | 
						|
        for i:=1 to nsects-1 do
 | 
						|
          if not FLoaded[i] then
 | 
						|
            LoadSection(shdrs[i],i,objdata);
 | 
						|
 | 
						|
        { load the content }
 | 
						|
        ReadSectionContent(objdata);
 | 
						|
 | 
						|
        { load the symtable }
 | 
						|
        FReader.Seek(symtaboffset+sizeof(TElfSymbol));
 | 
						|
        LoadSymbols(objdata,syms,localsyms);
 | 
						|
 | 
						|
        { finish relocations }
 | 
						|
        for i:=0 to objdata.ObjSectionList.Count-1 do
 | 
						|
          begin
 | 
						|
            objsec:=TObjSection(objdata.ObjsectionList[i]);
 | 
						|
            { skip debug sections }
 | 
						|
            if (oso_debug in objsec.SecOptions) and
 | 
						|
               (cs_link_strip in current_settings.globalswitches) and
 | 
						|
               not(cs_link_separate_dbg_file in current_settings.globalswitches) then
 | 
						|
              continue;
 | 
						|
 | 
						|
            if FSecTbl[objsec.index].relocpos>0 then
 | 
						|
              LoadRelocations(FSecTbl[objsec.index]);
 | 
						|
          end;
 | 
						|
 | 
						|
        { finish processing section groups, if any }
 | 
						|
        if Assigned(objdata.GroupsList) then
 | 
						|
          begin
 | 
						|
            for i:=0 to objdata.GroupsList.Count-1 do
 | 
						|
              begin
 | 
						|
                grp:=TObjSectionGroup(objData.GroupsList[i]);
 | 
						|
                FReader.Seek(shdrs[i+1].sh_offset);
 | 
						|
                { first dword is flags }
 | 
						|
                FReader.Read(tmp,sizeof(longword));
 | 
						|
                if source_info.endian<>target_info.endian then
 | 
						|
                  tmp:=SwapEndian(tmp);
 | 
						|
                if (tmp and GRP_COMDAT)<>0 then
 | 
						|
                  grp.IsComdat:=true;
 | 
						|
 | 
						|
                count:=(shdrs[i+1].sh_size div sizeof(longword))-1;
 | 
						|
                SetLength(grp.members,count);
 | 
						|
                for j:=0 to count-1 do
 | 
						|
                  begin
 | 
						|
                    FReader.Read(tmp,sizeof(longword));
 | 
						|
                    if source_info.endian<>target_info.endian then
 | 
						|
                      tmp:=SwapEndian(tmp);
 | 
						|
                    if (tmp>=nsects) then
 | 
						|
                      InternalError(2012110805);
 | 
						|
                    objsec:=FSecTbl[tmp].sec;
 | 
						|
                    if (objsec=nil) then
 | 
						|
                      InternalError(2012110806);
 | 
						|
                    if (TElfObjSection(objsec).shflags and SHF_GROUP)=0 then
 | 
						|
                      InternalError(2012110807);
 | 
						|
                    grp.members[j]:=objsec;
 | 
						|
                    objsec.Group:=grp;
 | 
						|
                  end;
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
 | 
						|
        result:=True;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    class function TElfObjInput.CanReadObjData(AReader:TObjectreader):boolean;
 | 
						|
      var
 | 
						|
        header: TElfHeader;
 | 
						|
      begin
 | 
						|
        result:=false;
 | 
						|
        if AReader.Read(header,sizeof(header)) then
 | 
						|
          begin;
 | 
						|
            if (header.e_ident[EI_MAG0]=ELFMAG0) and (header.e_ident[EI_MAG1]=ELFMAG1) and
 | 
						|
               (header.e_ident[EI_MAG2]=ELFMAG2) and (header.e_ident[EI_MAG3]=ELFMAG3) then
 | 
						|
            { TODO: check additional fields }
 | 
						|
              result:=true;
 | 
						|
          end;
 | 
						|
        AReader.Seek(0);
 | 
						|
      end;
 | 
						|
 | 
						|
{*****************************************************************************
 | 
						|
                                  TElfExeOutput
 | 
						|
*****************************************************************************}
 | 
						|
 | 
						|
    constructor TElfExeOutput.Create;
 | 
						|
      begin
 | 
						|
        inherited Create;
 | 
						|
        CObjData:=TElfObjData;
 | 
						|
        CExeSection:=TElfExeSection;
 | 
						|
{$ifdef cpu64}
 | 
						|
        MaxMemPos:=Qword($FFFFFFFFFFFFFFFF);
 | 
						|
        //MaxMemPos:=$7EFFFFFF;   { As specified by SysV AMD64 ABI for small memory model }
 | 
						|
{$else cpu64}
 | 
						|
        MaxMemPos:=$7FFFFFFF;
 | 
						|
{$endif cpu64}
 | 
						|
        SectionMemAlign:=$20;
 | 
						|
        SectionDataAlign:=$20;
 | 
						|
        segmentlist:=TFPObjectList.Create(True);
 | 
						|
        neededlist:=TFPHashList.Create;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    destructor TElfExeOutput.Destroy;
 | 
						|
      begin
 | 
						|
        dyncopysyms.Free;
 | 
						|
        neededlist.Free;
 | 
						|
        segmentlist.Free;
 | 
						|
        dynsymlist.Free;
 | 
						|
        dynreloclist.Free;
 | 
						|
        if assigned(dynsymnames) then
 | 
						|
          FreeMem(dynsymnames);
 | 
						|
        stringdispose(FInterpreter);
 | 
						|
        inherited Destroy;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function TElfExeOutput.AttachSection(objsec:TObjSection):TElfExeSection;
 | 
						|
      begin
 | 
						|
        objsec.SecOptions:=[oso_keep];
 | 
						|
        result:=TElfExeSection(FindExeSection(objsec.name));
 | 
						|
        if result=nil then
 | 
						|
          result:=TElfExeSection.Create(ExeSectionList,objsec.name);
 | 
						|
        result.AddObjSection(objsec);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function TElfExeOutput.CreateSegment(atype,aflags,aalign:longword):TElfSegment;
 | 
						|
      begin
 | 
						|
        result:=TElfSegment.Create(atype,aflags,aalign);
 | 
						|
        segmentlist.add(result);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.WriteHeader;
 | 
						|
      var
 | 
						|
        header: TElfHeader;
 | 
						|
      begin
 | 
						|
        FillChar(header,sizeof(header),0);
 | 
						|
        header.e_ident[EI_MAG0]:=ELFMAG0; { = #127'ELF' }
 | 
						|
        header.e_ident[EI_MAG1]:=ELFMAG1;
 | 
						|
        header.e_ident[EI_MAG2]:=ELFMAG2;
 | 
						|
        header.e_ident[EI_MAG3]:=ELFMAG3;
 | 
						|
        header.e_ident[EI_CLASS]:=ELFCLASS;
 | 
						|
        if target_info.endian=endian_big then
 | 
						|
          header.e_ident[EI_DATA]:=ELFDATA2MSB
 | 
						|
        else
 | 
						|
          header.e_ident[EI_DATA]:=ELFDATA2LSB;
 | 
						|
 | 
						|
        header.e_ident[EI_VERSION]:=1;
 | 
						|
        if IsSharedLibrary then
 | 
						|
          header.e_type:=ET_DYN
 | 
						|
        else
 | 
						|
          header.e_type:=ET_EXEC;
 | 
						|
        header.e_machine:=ElfTarget.machine_code;
 | 
						|
        header.e_version:=1;
 | 
						|
        header.e_phoff:=sizeof(TElfHeader);
 | 
						|
        header.e_shoff:=shoffset;
 | 
						|
        header.e_shstrndx:=ExeSectionList.IndexOf(shstrtabsect.ExeSection)+1;
 | 
						|
 | 
						|
        header.e_shnum:=ExeSectionList.Count+1;
 | 
						|
        header.e_phnum:=segmentlist.count;
 | 
						|
        header.e_ehsize:=sizeof(telfheader);
 | 
						|
        if assigned(EntrySym) then
 | 
						|
          header.e_entry:=EntrySym.Address;
 | 
						|
        header.e_shentsize:=sizeof(telfsechdr);
 | 
						|
        header.e_phentsize:=sizeof(telfproghdr);
 | 
						|
        MaybeSwapHeader(header);
 | 
						|
        FWriter.Write(header,sizeof(header));
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.exesection_write_header(p:TObject;arg:Pointer);
 | 
						|
      var
 | 
						|
        shdr: TElfsechdr;
 | 
						|
        exesec: TElfExeSection absolute p;
 | 
						|
      begin
 | 
						|
        FillChar(shdr,sizeof(shdr),0);
 | 
						|
        shdr.sh_name:=exesec.shstridx;
 | 
						|
        if (ExeWriteMode=ewm_dbgonly) and
 | 
						|
           (exesec.SecOptions*[oso_debug,oso_debug_copy]=[]) then
 | 
						|
          shdr.sh_type:=SHT_NOBITS
 | 
						|
        else
 | 
						|
          shdr.sh_type:=exesec.shtype;
 | 
						|
        shdr.sh_flags:=exesec.shflags;
 | 
						|
        if (oso_load in exesec.SecOptions) then
 | 
						|
          shdr.sh_addr:=exesec.MemPos;
 | 
						|
        shdr.sh_offset:=exesec.DataPos;
 | 
						|
        shdr.sh_size:=exesec.Size;
 | 
						|
        shdr.sh_link:=exesec.shlink;
 | 
						|
        shdr.sh_info:=exesec.shinfo;
 | 
						|
        shdr.sh_addralign:=exesec.SecAlign;
 | 
						|
        shdr.sh_entsize:=exesec.shentsize;
 | 
						|
        MaybeSwapSecHeader(shdr);
 | 
						|
        FWriter.Write(shdr,sizeof(shdr));
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.segment_write_header(p:TObject;arg:Pointer);
 | 
						|
      var
 | 
						|
        phdr: TElfproghdr;
 | 
						|
        seg: TElfSegment absolute p;
 | 
						|
      begin
 | 
						|
        FillChar(phdr,sizeof(phdr),0);
 | 
						|
        phdr.p_type:=seg.ptype;
 | 
						|
        phdr.p_flags:=seg.pflags;
 | 
						|
        phdr.p_align:=seg.align;
 | 
						|
        phdr.p_offset:=seg.DataPos;
 | 
						|
        phdr.p_filesz:=seg.DataSize;
 | 
						|
        phdr.p_memsz:=seg.MemSize;
 | 
						|
        phdr.p_vaddr:=seg.MemPos;
 | 
						|
        phdr.p_paddr:=seg.MemPos;
 | 
						|
 | 
						|
        MaybeSwapHeader(phdr);
 | 
						|
        FWriter.Write(phdr,sizeof(phdr));
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.WriteStaticSymtable;
 | 
						|
      var
 | 
						|
        i: longint;
 | 
						|
        sec: TElfExeSection;
 | 
						|
        exesym: TExeSymbol;
 | 
						|
      begin
 | 
						|
        if assigned(tlsseg) then
 | 
						|
          symtab.tlsbase:=tlsseg.MemPos;
 | 
						|
        for i:=0 to ExeSectionList.Count-1 do
 | 
						|
          begin
 | 
						|
            sec:=TElfExeSection(ExeSectionList[i]);
 | 
						|
            { Must not write symbols for internal sections like .symtab }
 | 
						|
            if (sec.shtype in [SHT_SYMTAB,SHT_STRTAB,SHT_REL,SHT_RELA]) then
 | 
						|
              continue;
 | 
						|
            sec.secsymidx:=symtab.symidx;
 | 
						|
            symtab.writeInternalSymbol(sec.mempos,0,STT_SECTION,sec.secshidx);
 | 
						|
          end;
 | 
						|
        { local symbols first }
 | 
						|
        for i:=0 to ExeSymbolList.Count-1 do
 | 
						|
          begin
 | 
						|
            exesym:=TExeSymbol(ExeSymbolList[i]);
 | 
						|
            if (exesym.objsymbol.bind=AB_LOCAL) and (exesym.objsymbol.typ<>AT_LABEL) then
 | 
						|
              symtab.WriteSymbol(exesym.objsymbol);
 | 
						|
          end;
 | 
						|
        { Global Symbols }
 | 
						|
        for i:=0 to ExeSymbolList.Count-1 do
 | 
						|
          begin
 | 
						|
            exesym:=TExeSymbol(ExeSymbolList[i]);
 | 
						|
            if (exesym.objsymbol.bind<>AB_LOCAL) then
 | 
						|
              symtab.WriteSymbol(exesym.objsymbol);
 | 
						|
          end;
 | 
						|
        { update exe section properties }
 | 
						|
        symtab.ExeSection.size:=symtab.size;
 | 
						|
        TElfExeSection(symtab.ExeSection).shinfo:=symtab.shinfo;
 | 
						|
        TElfExeSection(symtab.ExeSection).shlink:=ExeSectionList.IndexOf(symtab.fstrsec.ExeSection)+1;
 | 
						|
        symtab.fstrsec.ExeSection.Size:=symtab.fstrsec.size;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.MapSectionsToSegments;
 | 
						|
      var
 | 
						|
        seg: TElfSegment;
 | 
						|
        exesec: TExeSection;
 | 
						|
        i: longint;
 | 
						|
      begin
 | 
						|
        if (not IsSharedLibrary) and assigned(interpobjsec) then
 | 
						|
          begin
 | 
						|
            phdrseg:=CreateSegment(PT_PHDR,PF_R or PF_X,sizeof(pint));
 | 
						|
            seg:=CreateSegment(PT_INTERP,PF_R,1);
 | 
						|
            seg.Add(interpobjsec.ExeSection);
 | 
						|
          end;
 | 
						|
 | 
						|
        textseg:=CreateSegment(PT_LOAD,PF_X or PF_R,ElfTarget.max_page_size);
 | 
						|
        dataseg:=CreateSegment(PT_LOAD,PF_R or PF_W,ElfTarget.max_page_size);
 | 
						|
        for i:=0 to ExeSectionList.Count-1 do
 | 
						|
          begin
 | 
						|
            exesec:=TExeSection(ExeSectionList[i]);
 | 
						|
            if (oso_load in exesec.SecOptions) then
 | 
						|
              begin
 | 
						|
                if (TElfExeSection(exesec).shflags and SHF_TLS)<>0 then
 | 
						|
                  begin
 | 
						|
                    if tlsseg=nil then
 | 
						|
                      tlsseg:=CreateSegment(PT_TLS,PF_R,sizeof(pint));
 | 
						|
                    tlsseg.add(exesec);
 | 
						|
                  end;
 | 
						|
 | 
						|
                { TODO: at least on Linux, ld seems to drop .note.ABI-tag for static executables.
 | 
						|
                  (Logic is as follows: there is no .note.ABI-tag section in ld script, so it
 | 
						|
                  is processed as orphan section. As such, it is placed after .interp.
 | 
						|
                  For static executables .interp is dropped, and it looks like there's nowhere to
 | 
						|
                  place .note.ABI-tag in this case)
 | 
						|
                  Always including it doesn't harm though (except increasing file size). }
 | 
						|
                if TElfExeSection(exesec).shtype=SHT_NOTE then
 | 
						|
                  begin
 | 
						|
                    if noteseg=nil then
 | 
						|
                      noteseg:=CreateSegment(PT_NOTE,PF_R,4);
 | 
						|
                    noteseg.Add(exesec);
 | 
						|
                    Include(exesec.SecOptions,oso_debug_copy);
 | 
						|
                  end;
 | 
						|
                if (oso_executable in exesec.SecOptions) or
 | 
						|
                  not (oso_write in exesec.SecOptions) then
 | 
						|
                  textseg.add(exesec)
 | 
						|
                else
 | 
						|
                  dataseg.add(exesec);
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
 | 
						|
        if dynamiclink then
 | 
						|
          begin
 | 
						|
            seg:=CreateSegment(PT_DYNAMIC,PF_R or PF_W,sizeof(pint));
 | 
						|
            seg.add(dynamicsec.ExeSection);
 | 
						|
          end;
 | 
						|
 | 
						|
        { stack flags }
 | 
						|
        CreateSegment(PT_GNU_STACK,PF_R or PF_W or (PF_X*ord(ExecStack)),sizeof(pint));
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.make_dynamic_if_undefweak(exesym:TExeSymbol);
 | 
						|
      begin
 | 
						|
        if (exesym.dynindex=0) and (exesym.state=symstate_undefweak) and
 | 
						|
          not (cs_link_staticflag in current_settings.globalswitches) then
 | 
						|
          exesym.dynindex:=dynsymlist.add(exesym)+1;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function TElfExeOutput.AllocGOTSlot(objsym:TObjSymbol):boolean;
 | 
						|
      var
 | 
						|
        exesym: TExeSymbol;
 | 
						|
      begin
 | 
						|
        result:=false;
 | 
						|
        exesym:=objsym.exesymbol;
 | 
						|
 | 
						|
        { Although local symbols should not be accessed through GOT,
 | 
						|
          this isn't strictly forbidden. In this case we need to fake up
 | 
						|
          the exesym to store the GOT offset in it.
 | 
						|
          TODO: name collision; maybe use a different symbol list object? }
 | 
						|
        if exesym=nil then
 | 
						|
          begin
 | 
						|
            exesym:=TExeSymbol.Create(ExeSymbolList,objsym.name+'*local*');
 | 
						|
            exesym.objsymbol:=objsym;
 | 
						|
            objsym.exesymbol:=exesym;
 | 
						|
          end;
 | 
						|
        if exesym.GotOffset>0 then
 | 
						|
          exit;
 | 
						|
        gotobjsec.alloc(sizeof(pint));
 | 
						|
        exesym.GotOffset:=gotobjsec.size;
 | 
						|
        make_dynamic_if_undefweak(exesym);
 | 
						|
        { In shared library, every GOT entry needs a RELATIVE dynamic reloc,
 | 
						|
          imported/exported symbols need GLOB_DAT instead. For executables,
 | 
						|
          only the latter applies. }
 | 
						|
        if IsSharedLibrary or (exesym.dynindex>0) then
 | 
						|
          dynrelocsec.alloc(dynrelocsec.shentsize);
 | 
						|
        result:=true;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.PrepareGOT;
 | 
						|
      var
 | 
						|
        i,j,k: longint;
 | 
						|
        objsec: TElfObjSection;
 | 
						|
        exesec: TExeSection;
 | 
						|
      begin
 | 
						|
        for i:=0 to ExeSectionList.Count-1 do
 | 
						|
          begin
 | 
						|
            exesec:=TExeSection(ExeSectionList[i]);
 | 
						|
            for j:=0 to exesec.ObjSectionlist.count-1 do
 | 
						|
              begin
 | 
						|
                objsec:=TElfObjSection(exesec.ObjSectionlist[j]);
 | 
						|
                { ignore linker-generated and debug sections }
 | 
						|
                if (objsec.objdata=internalobjdata) or (oso_debug in objsec.SecOptions) then
 | 
						|
                  continue;
 | 
						|
                if not objsec.Used then
 | 
						|
                  internalerror(2012060901);
 | 
						|
                k:=0;
 | 
						|
                while k<objsec.ObjRelocations.Count do
 | 
						|
                  begin
 | 
						|
                    GOTRelocPass1(objsec,k);
 | 
						|
                    inc(k);
 | 
						|
                  end;
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
        { remember sizes for sanity checking }
 | 
						|
        gotsize:=gotobjsec.size;
 | 
						|
        if assigned(dynrelocsec) then
 | 
						|
          dynrelsize:=dynrelocsec.size
 | 
						|
        else
 | 
						|
          dynrelsize:=0;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.CreateGOTSection;
 | 
						|
      begin
 | 
						|
        gotpltobjsec:=TElfObjSection.create_ext(internalObjData,'.got.plt',
 | 
						|
          SHT_PROGBITS,SHF_ALLOC or SHF_WRITE,sizeof(pint),sizeof(pint));
 | 
						|
 | 
						|
        gotobjsec:=TElfObjSection.create_ext(internalObjData,'.got',
 | 
						|
            SHT_PROGBITS,SHF_ALLOC or SHF_WRITE,sizeof(pint),sizeof(pint));
 | 
						|
        gotobjsec.SecOptions:=[oso_keep];
 | 
						|
 | 
						|
        { GOT symbol and reserved .got.plt entries }
 | 
						|
        internalObjData.SetSection(gotpltobjsec);
 | 
						|
        gotsymbol:=internalObjData.SymbolDefine('_GLOBAL_OFFSET_TABLE_',AB_GLOBAL,AT_DATA);
 | 
						|
        gotpltobjsec.writeZeros(3*sizeof(pint));
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.Load_Start;
 | 
						|
      begin
 | 
						|
        inherited Load_Start;
 | 
						|
        dynsymlist:=TFPObjectList.Create(False);
 | 
						|
        CreateGOTSection;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.Load_DynamicObject(objdata:TObjData;asneeded:boolean);
 | 
						|
      var
 | 
						|
        i: longint;
 | 
						|
        exesym: TExeSymbol;
 | 
						|
        objsym: TObjSymbol;
 | 
						|
        needed: boolean;
 | 
						|
      begin
 | 
						|
        Comment(v_debug,'Dynamic object: '+objdata.name);
 | 
						|
        needed:=false;
 | 
						|
        for i:=0 to UnresolvedExeSymbols.Count-1 do
 | 
						|
          begin
 | 
						|
            exesym:=TExeSymbol(UnresolvedExeSymbols[i]);
 | 
						|
            if not (exesym.State in [symstate_undefined,symstate_undefweak]) then
 | 
						|
              continue;
 | 
						|
            objsym:=TObjSymbol(objdata.ObjSymbolList.Find(exesym.name));
 | 
						|
            if assigned(objsym) then
 | 
						|
              begin
 | 
						|
                exesym.State:=symstate_defined;
 | 
						|
                exesym.dynindex:=dynsymlist.Add(exesym)+1;
 | 
						|
                { The original binding, value and section of external symbol
 | 
						|
                  must be preserved, therefore resolving directly to .so symbol
 | 
						|
                  hurts more than it helps. Copy type and size, and store .so
 | 
						|
                  symbol in objsym.indsymbol for later use. }
 | 
						|
                exesym.ObjSymbol.typ:=objsym.typ;
 | 
						|
                if objsym.typ<>AT_FUNCTION then
 | 
						|
                  exesym.ObjSymbol.size:=objsym.size;
 | 
						|
                exesym.ObjSymbol.indsymbol:=objsym;
 | 
						|
                objsym.ExeSymbol:=exesym;
 | 
						|
                needed:=true;
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
        if (needed or (not asneeded)) and
 | 
						|
          (neededlist.Find(objdata.name)=nil) then
 | 
						|
          neededlist.Add(objdata.name,objdata);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.Order_Start;
 | 
						|
      begin
 | 
						|
        inherited Order_Start;
 | 
						|
        dynamiclink:=IsSharedLibrary or (dynsymlist.count>0) or
 | 
						|
          (
 | 
						|
            (UnresolvedExeSymbols.Count>0) and
 | 
						|
            not (cs_link_staticflag in current_settings.globalswitches)
 | 
						|
          );
 | 
						|
        if dynamiclink then
 | 
						|
          InitDynlink;
 | 
						|
        if dynamiclink or (IndirectObjSymbols.Count>0) then
 | 
						|
          CreatePLT;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.Order_end;
 | 
						|
 | 
						|
      procedure set_oso_keep(const s:string);
 | 
						|
        var
 | 
						|
          exesec:TExeSection;
 | 
						|
          objsec:TObjSection;
 | 
						|
          i:longint;
 | 
						|
        begin
 | 
						|
          exesec:=TExeSection(ExeSectionList.Find(s));
 | 
						|
          if assigned(exesec) then
 | 
						|
            begin
 | 
						|
              for i:=0 to exesec.ObjSectionList.Count-1 do
 | 
						|
                begin
 | 
						|
                  objsec:=TObjSection(exesec.ObjSectionList[i]);
 | 
						|
                  { ignore sections used for symbol definition }
 | 
						|
                  if oso_data in objsec.SecOptions then
 | 
						|
                    objsec.SecOptions:=[oso_keep];
 | 
						|
                end;
 | 
						|
            end;
 | 
						|
        end;
 | 
						|
 | 
						|
      begin
 | 
						|
        OrderOrphanSections;
 | 
						|
        inherited Order_end;
 | 
						|
        set_oso_keep('.init');
 | 
						|
        set_oso_keep('.fini');
 | 
						|
        set_oso_keep('.jcr');
 | 
						|
        set_oso_keep('.ctors');
 | 
						|
        set_oso_keep('.dtors');
 | 
						|
        set_oso_keep('.preinit_array');
 | 
						|
        set_oso_keep('.init_array');
 | 
						|
        set_oso_keep('.fini_array');
 | 
						|
        set_oso_keep('.eh_frame');
 | 
						|
 | 
						|
        { let .dynamic reference other dynamic sections so they aren't marked
 | 
						|
          for removal as unused }
 | 
						|
        if dynamiclink then
 | 
						|
          WriteDynamicTags;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.OrderOrphanSections;
 | 
						|
      var
 | 
						|
        i,j:longint;
 | 
						|
        objdata:TObjData;
 | 
						|
        objsec:TObjSection;
 | 
						|
        exesec:TExeSection;
 | 
						|
        opts:TObjSectionOptions;
 | 
						|
        s:string;
 | 
						|
        newsections,tmp:TFPHashObjectList;
 | 
						|
        allsections:TFPList;
 | 
						|
        inserts:array[0..6] of TExeSection;
 | 
						|
        idx,inspos:longint;
 | 
						|
      begin
 | 
						|
        newsections:=TFPHashObjectList.Create(false);
 | 
						|
        allsections:=TFPList.Create;
 | 
						|
        { copy existing sections }
 | 
						|
        for i:=0 to ExeSectionList.Count-1 do
 | 
						|
          allsections.add(ExeSectionList[i]);
 | 
						|
        inserts[0]:=FindExeSection('.comment');
 | 
						|
        inserts[1]:=nil;
 | 
						|
        inserts[2]:=FindExeSection('.interp');
 | 
						|
        inserts[3]:=FindExeSection('.bss');
 | 
						|
        inserts[4]:=FindExeSection('.data');
 | 
						|
        inserts[5]:=FindExeSection('.rodata');
 | 
						|
        inserts[6]:=FindExeSection('.text');
 | 
						|
 | 
						|
        for i:=0 to ObjDataList.Count-1 do
 | 
						|
          begin
 | 
						|
            ObjData:=TObjData(ObjDataList[i]);
 | 
						|
            for j:=0 to ObjData.ObjSectionList.Count-1 do
 | 
						|
              begin
 | 
						|
                objsec:=TObjSection(ObjData.ObjSectionList[j]);
 | 
						|
                if objsec.Used then
 | 
						|
                  continue;
 | 
						|
                s:=objsec.name;
 | 
						|
                exesec:=TExeSection(newsections.Find(s));
 | 
						|
                if assigned(exesec) then
 | 
						|
                  begin
 | 
						|
                    exesec.AddObjSection(objsec);
 | 
						|
                    continue;
 | 
						|
                  end;
 | 
						|
                opts:=objsec.SecOptions*[oso_data,oso_load,oso_write,oso_executable];
 | 
						|
                if (objsec.SecOptions*[oso_load,oso_debug]=[]) then
 | 
						|
                  { non-alloc, after .comment
 | 
						|
                    GNU ld places .comment between stabs and dwarf debug info }
 | 
						|
                  inspos:=0
 | 
						|
                else if not (oso_load in objsec.SecOptions) then
 | 
						|
                  inspos:=1   { debugging, skip }
 | 
						|
                else if (oso_load in objsec.SecOptions) and
 | 
						|
                  (TElfObjSection(objsec).shtype=SHT_NOTE) then
 | 
						|
                  inspos:=2   { after .interp }
 | 
						|
                else if (opts=[oso_load,oso_write]) then
 | 
						|
                  inspos:=3   { after .bss }
 | 
						|
                else if (opts=[oso_data,oso_load,oso_write]) then
 | 
						|
                  inspos:=4   { after .data }
 | 
						|
                else if (opts=[oso_data,oso_load]) then
 | 
						|
                  inspos:=5   { rodata, relocs=??? }
 | 
						|
                else if (opts=[oso_data,oso_load,oso_executable]) then
 | 
						|
                  inspos:=6   { text }
 | 
						|
                else
 | 
						|
                  begin
 | 
						|
                    Comment(v_debug,'Orphan section '+objsec.fullname+' has attributes that are not handled!');
 | 
						|
                    continue;
 | 
						|
                  end;
 | 
						|
                if (inserts[inspos]=nil) then
 | 
						|
                  begin
 | 
						|
                    Comment(v_debug,'Orphan section '+objsec.fullname+': nowhere to insert, ignored');
 | 
						|
                    continue;
 | 
						|
                  end;
 | 
						|
                idx:=allsections.IndexOf(inserts[inspos]);
 | 
						|
                exesec:=CExeSection.Create(newsections,s);
 | 
						|
                allsections.Insert(idx+1,exesec);
 | 
						|
                inserts[inspos]:=exesec;
 | 
						|
                exesec.AddObjSection(objsec);
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
        { Now replace the ExeSectionList with content of allsections }
 | 
						|
        if (newsections.count<>0) then
 | 
						|
          ReplaceExeSectionList(allsections);
 | 
						|
        newsections.Free;
 | 
						|
        allsections.Free;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.AfterUnusedSectionRemoval;
 | 
						|
      var
 | 
						|
        i:longint;
 | 
						|
        exesym:TExeSymbol;
 | 
						|
        objsym:TObjSymbol;
 | 
						|
        objsec: TObjSection;
 | 
						|
      begin
 | 
						|
        { Unused section removal sets Used property of referenced exesymbols.
 | 
						|
          Remaining ones can be removed. }
 | 
						|
        for i:=0 to dynsymlist.count-1 do
 | 
						|
          begin
 | 
						|
            exesym:=TExeSymbol(dynsymlist[i]);
 | 
						|
            if assigned(exesym.ObjSymbol.ObjSection) then  // an exported symbol
 | 
						|
              continue;
 | 
						|
            if not exesym.used then
 | 
						|
              begin
 | 
						|
                dynsymlist[i]:=nil;
 | 
						|
                exesym.dynindex:=0;
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
        dynsymlist.Pack;
 | 
						|
        { reindex }
 | 
						|
        for i:=0 to dynsymlist.count-1 do
 | 
						|
          TExeSymbol(dynsymlist[i]).dynindex:=i+1;
 | 
						|
 | 
						|
        { Drop unresolved symbols that aren't referenced, assign dynamic
 | 
						|
          indices to remaining ones, but not if linking with -Xt.
 | 
						|
          TODO: behavior of .so with -Xt ? }
 | 
						|
        if (cs_link_staticflag in current_settings.globalswitches) then
 | 
						|
          UnresolvedExeSymbols.Clear
 | 
						|
        else
 | 
						|
        for i:=0 to UnresolvedExeSymbols.Count-1 do
 | 
						|
          begin
 | 
						|
            exesym:=TExeSymbol(UnresolvedExeSymbols[i]);
 | 
						|
            if exesym.used then
 | 
						|
              begin
 | 
						|
                if exesym.dynindex<>0 then
 | 
						|
                  InternalError(2012062301);
 | 
						|
                { Weak-referenced symbols are changed into dynamic ones
 | 
						|
                  only if referenced through GOT or PLT (this is BFD-compatible) }
 | 
						|
                if exesym.state<>symstate_undefweak then
 | 
						|
                  exesym.dynindex:=dynsymlist.add(exesym)+1;
 | 
						|
              end
 | 
						|
            else
 | 
						|
              UnresolvedExeSymbols[i]:=nil;
 | 
						|
          end;
 | 
						|
        UnresolvedExeSymbols.Pack;
 | 
						|
 | 
						|
        { Scan relocations to determine size of GOT, dynamic reloc section, etc. }
 | 
						|
        PrepareGOT;
 | 
						|
 | 
						|
        { Write required PLT entries }
 | 
						|
        for i:=0 to dynsymlist.Count-1 do
 | 
						|
          begin
 | 
						|
            exesym:=TExeSymbol(dynsymlist[i]);
 | 
						|
            if assigned(exesym.ObjSymbol.objsection) then  // an exported symbol
 | 
						|
              continue;
 | 
						|
 | 
						|
            if ((exesym.ObjSymbol.refs and symref_plt)<>0) or
 | 
						|
              ((exesym.ObjSymbol.typ=AT_FUNCTION) and (not IsSharedLibrary)) then
 | 
						|
              begin
 | 
						|
                make_dynamic_if_undefweak(exesym);
 | 
						|
 | 
						|
                { This symbol has a valid address to which relocations are resolved,
 | 
						|
                  but it remains (weak)external when written to dynamic symtable. }
 | 
						|
                objsym:=internalobjdata.CreateSymbol(exesym.name);
 | 
						|
                objsym.typ:=AT_FUNCTION;
 | 
						|
                objsym.bind:=exesym.ObjSymbol.bind;  { AB_EXTERNAL or AB_WEAK_EXTERNAL }
 | 
						|
                objsym.indsymbol:=exesym.ObjSymbol.indsymbol;
 | 
						|
                objsym.offset:=pltobjsec.size;
 | 
						|
                objsym.objsection:=pltobjsec;
 | 
						|
                objsym.exesymbol:=exesym;
 | 
						|
                exesym.ObjSymbol:=objsym;
 | 
						|
 | 
						|
                WritePLTEntry(exesym);
 | 
						|
              end
 | 
						|
            else if ((exesym.ObjSymbol.refs and symref_from_text)<>0) and
 | 
						|
              (exesym.ObjSymbol.typ<>AT_FUNCTION) and (not IsSharedLibrary) and
 | 
						|
              (exesym.state<>symstate_undefweak) then
 | 
						|
              begin
 | 
						|
                if exesym.ObjSymbol.size=0 then
 | 
						|
                  Comment(v_error,'Dynamic variable '+exesym.name+' has zero size');
 | 
						|
                internalobjdata.setSection(dynbssobjsec);
 | 
						|
                internalobjdata.allocalign(size_2_align(exesym.ObjSymbol.size));
 | 
						|
                objsym:=internalobjdata.SymbolDefine(exesym.name,AB_GLOBAL,AT_DATA);
 | 
						|
                objsym.size:=exesym.ObjSymbol.size;
 | 
						|
                objsym.indsymbol:=exesym.ObjSymbol.indsymbol;
 | 
						|
                exesym.ObjSymbol:=objsym;
 | 
						|
                objsym.exesymbol:=exesym;
 | 
						|
                dynbssobjsec.alloc(objsym.size);
 | 
						|
                { allocate space for R_xx_COPY relocation for this symbol;
 | 
						|
                  we'll create it later, to be consistent with "-z combreloc" semantics }
 | 
						|
                dyncopysyms.add(objsym);
 | 
						|
                dynrelocsec.alloc(dynrelocsec.shentsize);
 | 
						|
                inc(dynrelsize,dynrelocsec.shentsize);
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
 | 
						|
        { Handle indirect symbols }
 | 
						|
        for i:=0 to IndirectObjSymbols.Count-1 do
 | 
						|
          begin
 | 
						|
            objsym:=TObjSymbol(IndirectObjSymbols[i]);
 | 
						|
            objsec:=objsym.ExeSymbol.ObjSymbol.objsection;
 | 
						|
            objsym.bind:=AB_EXTERNAL;  { cheat FixupSymbols }
 | 
						|
            if (oso_plt in objsec.SecOptions) then
 | 
						|
              continue;
 | 
						|
            WriteIndirectPLTEntry(objsym.ExeSymbol);
 | 
						|
          end;
 | 
						|
 | 
						|
        FixupSymbols;
 | 
						|
 | 
						|
        if dynamiclink then
 | 
						|
          begin
 | 
						|
            WriteVersionSections;
 | 
						|
            WriteDynamicSymbolsHash;
 | 
						|
          end;
 | 
						|
 | 
						|
        { Create .shstrtab section, which is needed in both exe and .dbg files }
 | 
						|
        shstrtabsect:=TElfObjSection.Create_ext(internalObjData,'.shstrtab',SHT_STRTAB,0,1,0);
 | 
						|
        shstrtabsect.SecOptions:=[oso_debug_copy];
 | 
						|
        AttachSection(shstrtabsect);
 | 
						|
 | 
						|
        { Create the static symtable (.symtab and .strtab) }
 | 
						|
        if (cs_link_separate_dbg_file in current_settings.globalswitches) or
 | 
						|
          not(cs_link_strip in current_settings.globalswitches) then
 | 
						|
          begin
 | 
						|
            symtab:=TElfSymtab.Create(internalObjData,esk_exe);
 | 
						|
            symtab.SecOptions:=[oso_debug];
 | 
						|
            symtab.fstrsec.SecOptions:=[oso_debug];
 | 
						|
            AttachSection(symtab);
 | 
						|
            AttachSection(symtab.fstrsec);
 | 
						|
          end;
 | 
						|
 | 
						|
        { Re-enable sections which end up to contain some data
 | 
						|
          (.got, .rel[a].dyn, .rel[a].plt (includes .rel[a].iplt) and .hash }
 | 
						|
        if gotobjsec.size<>0 then
 | 
						|
          gotobjsec.ExeSection.Disabled:=false;
 | 
						|
        if assigned(dynrelocsec) and
 | 
						|
          ((dynrelocsec.size<>0) or (dyncopysyms.count<>0)) then
 | 
						|
          dynrelocsec.ExeSection.Disabled:=false;
 | 
						|
        if assigned(pltrelocsec) and (pltrelocsec.size>0) then
 | 
						|
          pltrelocsec.ExeSection.Disabled:=false;
 | 
						|
        if assigned(ipltrelocsec) and (ipltrelocsec.size>0) then
 | 
						|
          ipltrelocsec.ExeSection.Disabled:=false;
 | 
						|
        if assigned(hashobjsec) then
 | 
						|
          hashobjsec.ExeSection.Disabled:=false;
 | 
						|
        if assigned(symversec) and (symversec.size<>0) then
 | 
						|
          symversec.ExeSection.Disabled:=false;
 | 
						|
        if assigned(verneedsec) and (verneedsec.size<>0) then
 | 
						|
          verneedsec.ExeSection.Disabled:=false;
 | 
						|
        if assigned(verdefsec) and (verdefsec.size<>0) then
 | 
						|
          verdefsec.ExeSection.Disabled:=false;
 | 
						|
 | 
						|
        RemoveDisabledSections;
 | 
						|
        MapSectionsToSegments;
 | 
						|
        if dynamiclink then
 | 
						|
          FinishDynamicTags;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.WriteShStrtab;
 | 
						|
      var
 | 
						|
        i: longint;
 | 
						|
        exesec: TElfExeSection;
 | 
						|
      begin
 | 
						|
        { Remove any existing .shstrtab contents }
 | 
						|
        if (shstrtabsect.size>0) then
 | 
						|
          begin
 | 
						|
            shstrtabsect.ReleaseData;
 | 
						|
            shstrtabsect.Size:=0;
 | 
						|
            shstrtabsect.SecOptions:=[oso_data];
 | 
						|
          end;
 | 
						|
 | 
						|
        shstrtabsect.writezeros(1);
 | 
						|
        for i:=0 to ExeSectionList.Count-1 do
 | 
						|
          begin
 | 
						|
            exesec:=TElfExeSection(ExeSectionList[i]);
 | 
						|
            exesec.shstridx:=shstrtabsect.writestr(exesec.Name);
 | 
						|
            exesec.secshidx:=i+1;
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.FixupSectionLinks;
 | 
						|
      var
 | 
						|
        dynstrndx,dynsymndx: longword;
 | 
						|
      begin
 | 
						|
        if dynamiclink then
 | 
						|
          begin
 | 
						|
            dynstrndx:=TElfExeSection(dynsymtable.fstrsec.ExeSection).secshidx;
 | 
						|
            dynsymndx:=TElfExeSection(dynsymtable.ExeSection).secshidx;
 | 
						|
            TElfExeSection(hashobjsec.ExeSection).shlink:=dynsymndx;
 | 
						|
            TElfExeSection(dynamicsec.ExeSection).shlink:=dynstrndx;
 | 
						|
            TElfExeSection(dynsymtable.ExeSection).shlink:=dynstrndx;
 | 
						|
 | 
						|
            if assigned(pltrelocsec) then
 | 
						|
              begin
 | 
						|
                TElfExeSection(pltrelocsec.ExeSection).shlink:=dynsymndx;
 | 
						|
                TElfExeSection(pltrelocsec.ExeSection).shinfo:=TElfExeSection(pltobjsec.ExeSection).secshidx;
 | 
						|
              end;
 | 
						|
 | 
						|
            if assigned(dynrelocsec) and assigned(dynrelocsec.ExeSection) then
 | 
						|
              TElfExeSection(dynrelocsec.ExeSection).shlink:=dynsymndx;
 | 
						|
 | 
						|
            if symversec.size>0 then
 | 
						|
              TElfExeSection(symversec.ExeSection).shlink:=dynsymndx;
 | 
						|
            if verdefsec.size>0 then
 | 
						|
              TElfExeSection(verdefsec.ExeSection).shlink:=dynstrndx;
 | 
						|
            if verneedsec.size>0 then
 | 
						|
              TElfExeSection(verneedsec.ExeSection).shlink:=dynstrndx;
 | 
						|
          end
 | 
						|
        else if assigned(ipltrelocsec) then
 | 
						|
          TElfExeSection(ipltrelocsec.ExeSection).shinfo:=TElfExeSection(pltobjsec.ExeSection).secshidx;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.Do_Mempos;
 | 
						|
      var
 | 
						|
        i,j: longint;
 | 
						|
        seg: TElfSegment;
 | 
						|
        exesec: TElfExeSection;
 | 
						|
        objsec: TObjSection;
 | 
						|
        tempmempos: qword;
 | 
						|
      begin
 | 
						|
        if IsSharedLibrary then
 | 
						|
          CurrMemPos:=0
 | 
						|
        else
 | 
						|
          CurrMemPos:=ElfTarget.exe_image_base;
 | 
						|
        textseg.MemPos:=CurrMemPos;
 | 
						|
        if assigned(phdrseg) then
 | 
						|
          begin
 | 
						|
            phdrseg.Mempos:=CurrMemPos+sizeof(TElfHeader);
 | 
						|
            phdrseg.Memsize:=sizeof(TElfproghdr)*segmentlist.count;
 | 
						|
          end;
 | 
						|
        CurrMemPos:=CurrMemPos+sizeof(TElfHeader)+segmentlist.count*sizeof(TElfproghdr);
 | 
						|
        MemPos_Segment(textseg);
 | 
						|
        CurrMemPos:=Align(CurrMemPos,SectionDataAlign); {! Data,not MemAlign}
 | 
						|
        CurrMemPos:=CurrMemPos+ElfTarget.max_page_size;
 | 
						|
        dataseg.MemPos:=CurrMemPos;
 | 
						|
        MemPos_Segment(dataseg);
 | 
						|
        { Mempos of unmapped sections is forced to zero, but we have to set positions
 | 
						|
          of its objsections and update sizes }
 | 
						|
        for i:=0 to ExeSectionList.Count-1 do
 | 
						|
          begin
 | 
						|
            exesec:=TElfExeSection(ExeSectionList[i]);
 | 
						|
            if not (oso_load in exesec.SecOptions) then
 | 
						|
              begin
 | 
						|
                tempmempos:=0;
 | 
						|
                exesec.MemPos:=tempmempos;
 | 
						|
                for j:=0 to exesec.ObjSectionList.Count-1 do
 | 
						|
                  begin
 | 
						|
                    objsec:=TObjSection(exesec.ObjSectionList[j]);
 | 
						|
                    tempmempos:=objsec.setmempos(tempmempos);
 | 
						|
                  end;
 | 
						|
                exesec.Size:=tempmempos;
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
 | 
						|
        { Update MemPos and MemSize of non-load segments,
 | 
						|
          in particular, TLS sizes are needed to resolve relocations }
 | 
						|
        for i:=0 to segmentlist.count-1 do
 | 
						|
          begin
 | 
						|
            seg:=TElfSegment(segmentlist[i]);
 | 
						|
            if (seg.ptype=PT_LOAD) or (seg.FSectionList.Count=0) then
 | 
						|
              continue;
 | 
						|
            seg.MemPos:=TExeSection(seg.FSectionList.First).MemPos;
 | 
						|
            for j:=0 to seg.FSectionList.Count-1 do
 | 
						|
              begin
 | 
						|
                exesec:=TElfExeSection(seg.FSectionList[j]);
 | 
						|
                seg.MemSize:=exesec.MemPos+exesec.Size-seg.MemPos;
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.MemPos_Start;
 | 
						|
      var
 | 
						|
        i: longint;
 | 
						|
      begin
 | 
						|
        { Assign section indices and fill .shstrtab
 | 
						|
          List of sections cannot be modified after this point. }
 | 
						|
        WriteShStrtab;
 | 
						|
 | 
						|
        { fixup sh_link/sh_info members of various dynamic sections }
 | 
						|
        FixupSectionLinks;
 | 
						|
 | 
						|
        { The actual layout }
 | 
						|
        Do_Mempos;
 | 
						|
 | 
						|
        if (not gotwritten) then
 | 
						|
          begin
 | 
						|
            { Reset size of .got and .rel[a].dyn, they will be refilled while fixing up relocations.
 | 
						|
              For .got, consider already written reserved entries. }
 | 
						|
            if assigned(gotobjsec) then
 | 
						|
              gotobjsec.size:=gotobjsec.data.size;
 | 
						|
            if assigned(dynrelocsec) then
 | 
						|
              begin
 | 
						|
                dynrelocsec.size:=0;
 | 
						|
                { write actual .dynsym content (needs valid symbol addresses) }
 | 
						|
                if assigned(tlsseg) then
 | 
						|
                  dynsymtable.tlsbase:=tlsseg.MemPos;
 | 
						|
                dynsymtable.size:=sizeof(TElfsymbol);
 | 
						|
                for i:=0 to dynsymlist.count-1 do
 | 
						|
                  dynsymtable.writeSymbol(TExeSymbol(dynsymlist[i]).objsymbol,dynsymnames[i]);
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.MemPos_Segment(seg:TElfSegment);
 | 
						|
      var
 | 
						|
        i: longint;
 | 
						|
        exesec: TElfExeSection;
 | 
						|
      begin
 | 
						|
        for i:=0 to seg.FSectionList.Count-1 do
 | 
						|
          begin
 | 
						|
            exesec:=TElfExeSection(seg.FSectionList[i]);
 | 
						|
            inherited MemPos_ExeSection(exesec);
 | 
						|
            { .tbss should not contribute to address space }
 | 
						|
            if (exesec.shtype=SHT_NOBITS) and ((exesec.shflags and SHF_TLS)<>0) then
 | 
						|
              CurrMemPos:=exesec.MemPos;
 | 
						|
          end;
 | 
						|
        { calculate size of the segment }
 | 
						|
        seg.MemSize:=CurrMemPos-seg.MemPos;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.MemPos_ExeSection(const aname:string);
 | 
						|
      begin
 | 
						|
        // Ignore. All layout is done in mempos_start
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.DataPos_Start;
 | 
						|
      var
 | 
						|
        i,j: longint;
 | 
						|
        exesec: TExeSection;
 | 
						|
        seg: TElfSegment;
 | 
						|
        objreloc: TObjRelocation;
 | 
						|
        objsym: TObjSymbol;
 | 
						|
      begin
 | 
						|
        gotwritten:=true;
 | 
						|
        { If target does not support sorted relocations, it is expected to write the
 | 
						|
          entire .rel[a].dyn section during FixupRelocations, and leave dynreloclist empty.
 | 
						|
          Otherwise, only RELATIVE ones should be written, space for non-relative relocations
 | 
						|
          should remain. }
 | 
						|
        if assigned(dynrelocsec) then
 | 
						|
          begin
 | 
						|
            { Append R_xx_COPY relocations }
 | 
						|
            for i:=0 to dyncopysyms.count-1 do
 | 
						|
              begin
 | 
						|
                objsym:=TObjSymbol(dyncopysyms[i]);
 | 
						|
                dynreloclist.Add(TObjRelocation.CreateRaw(objsym.address,objsym,ElfTarget.dyn_reloc_codes[dr_copy]));
 | 
						|
              end;
 | 
						|
            dyncopysyms.Clear;
 | 
						|
 | 
						|
            if (dynrelocsec.size+(dynreloclist.count*dynrelocsec.shentsize)<>dynrelsize) then
 | 
						|
              InternalError(2012110601);
 | 
						|
            { Write out non-RELATIVE dynamic relocations
 | 
						|
              TODO: additional sorting? }
 | 
						|
            for i:=0 to dynreloclist.count-1 do
 | 
						|
              begin
 | 
						|
                objreloc:=TObjRelocation(dynreloclist[i]);
 | 
						|
                WriteDynRelocEntry(objreloc.dataoffset,objreloc.ftype,objreloc.symbol.exesymbol.dynindex,0);
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
 | 
						|
        { sanity checks }
 | 
						|
        if assigned(gotobjsec) and (gotsize<>gotobjsec.size) then
 | 
						|
          InternalError(2012092501);
 | 
						|
        if assigned(dynrelocsec) and (dynrelsize<>dynrelocsec.size) then
 | 
						|
          InternalError(2012092502);
 | 
						|
 | 
						|
        if (ExeWriteMode=ewm_dbgonly) or
 | 
						|
          (
 | 
						|
            (ExeWriteMode=ewm_exefull) and
 | 
						|
             not(cs_link_strip in current_settings.globalswitches)
 | 
						|
          ) then
 | 
						|
          WriteStaticSymtable;
 | 
						|
 | 
						|
        { first handle primary segments }
 | 
						|
        textseg.DataPos:=0;
 | 
						|
        CurrDataPos:=sizeof(TElfHeader)+sizeof(TElfproghdr)*segmentlist.count;
 | 
						|
        if assigned(phdrseg) then
 | 
						|
          begin
 | 
						|
            phdrseg.DataPos:=sizeof(TElfHeader);
 | 
						|
            phdrseg.DataSize:=sizeof(TElfproghdr)*segmentlist.count;
 | 
						|
          end;
 | 
						|
        DataPos_Segment(textseg);
 | 
						|
        CurrDataPos:=align(CurrDataPos,SectionDataAlign);
 | 
						|
        dataseg.DataPos:=CurrDataPos;
 | 
						|
        DataPos_Segment(dataseg);
 | 
						|
        { then unmapped sections }
 | 
						|
        for i:=0 to ExeSectionList.Count-1 do
 | 
						|
          begin
 | 
						|
            exesec:=TExeSection(ExeSectionList[i]);
 | 
						|
            if not (oso_load in exesec.SecOptions) then
 | 
						|
              inherited DataPos_ExeSection(exesec);
 | 
						|
          end;
 | 
						|
        { finally, update size/position of non-load segments }
 | 
						|
        for i:=0 to segmentlist.count-1 do
 | 
						|
          begin
 | 
						|
            seg:=TElfSegment(segmentlist[i]);
 | 
						|
            if (seg.ptype=PT_LOAD) or (seg.FSectionList.Count=0) then
 | 
						|
              continue;
 | 
						|
            seg.DataPos:=TExeSection(seg.FSectionList.First).DataPos;
 | 
						|
            for j:=0 to seg.FSectionList.Count-1 do
 | 
						|
              begin
 | 
						|
                exesec:=TExeSection(seg.FSectionList[j]);
 | 
						|
                if oso_data in exesec.SecOptions then
 | 
						|
                  seg.DataSize:=exesec.DataPos+exesec.Size-seg.DataPos;
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
        { place section headers after the data }
 | 
						|
        shoffset:=CurrDataPos;
 | 
						|
        CurrDataPos:=CurrDataPos+ExeSectionList.Count*sizeof(TElfsechdr);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.DataPos_Segment(seg:TElfSegment);
 | 
						|
      var
 | 
						|
        i: longint;
 | 
						|
        exesec: TElfExeSection;
 | 
						|
      begin
 | 
						|
        for i:=0 to seg.FSectionList.Count-1 do
 | 
						|
          begin
 | 
						|
            exesec:=TElfExeSection(seg.FSectionList[i]);
 | 
						|
            { ELF needs DataPos set to 'would-be' value for sections that
 | 
						|
              don't have data, and for non-debug sections in .dbg file, too.
 | 
						|
              This slightly differs from generic approach. }
 | 
						|
            if not (oso_data in exesec.SecOptions) or
 | 
						|
              (
 | 
						|
                (ExeWriteMode=ewm_dbgonly) and
 | 
						|
                (exesec.SecOptions*[oso_debug,oso_debug_copy]=[])
 | 
						|
              ) then
 | 
						|
              begin
 | 
						|
                CurrDataPos:=align(CurrDataPos,SectionDataAlign);
 | 
						|
                exesec.DataPos:=CurrDataPos;
 | 
						|
              end
 | 
						|
            else
 | 
						|
              inherited DataPos_ExeSection(exesec);
 | 
						|
 | 
						|
          end;
 | 
						|
        { calculate size of the segment }
 | 
						|
        seg.DataSize:=CurrDataPos-seg.DataPos;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.DataPos_ExeSection(const aname:string);
 | 
						|
      begin
 | 
						|
        // Ignore. Work is done entirely in datapos_start.
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.InitDynlink;
 | 
						|
      begin
 | 
						|
        if not IsSharedLibrary then
 | 
						|
          begin
 | 
						|
            interpobjsec:=internalObjData.createsection('.interp',1,[oso_data,oso_load,oso_keep]);
 | 
						|
            interpobjsec.writestr(interpreter^);
 | 
						|
          end;
 | 
						|
 | 
						|
        hashobjsec:=TElfObjSection.create_ext(internalObjData,'.hash',
 | 
						|
          SHT_HASH,SHF_ALLOC,sizeof(pint),4);
 | 
						|
        hashobjsec.secoptions:=[oso_keep];
 | 
						|
 | 
						|
        dynsymtable:=TElfSymtab.create(internalObjData,esk_dyn);
 | 
						|
 | 
						|
        dynamicsec:=TElfObjSection.create_ext(internalObjData,'.dynamic',
 | 
						|
          SHT_DYNAMIC,SHF_ALLOC or SHF_WRITE,sizeof(pint),sizeof(TElfDyn));
 | 
						|
        dynamicsec.SecOptions:=[oso_keep];
 | 
						|
 | 
						|
        dynrelocsec:=TElfObjSection.create_reloc(internalObjData,'.dyn',true);
 | 
						|
        dynrelocsec.SecOptions:=[oso_keep];
 | 
						|
 | 
						|
        dynbssobjsec:=TElfObjSection.create_ext(internalObjData,'.dynbss',
 | 
						|
          SHT_NOBITS,SHF_ALLOC or SHF_WRITE,sizeof(pint){16??},0);
 | 
						|
        dynbssobjsec.SecOptions:=[oso_keep];
 | 
						|
 | 
						|
        dynreloclist:=TFPObjectList.Create(true);
 | 
						|
 | 
						|
        symversec:=TElfObjSection.create_ext(internalObjData,'.gnu.version',
 | 
						|
          SHT_GNU_VERSYM,SHF_ALLOC,sizeof(word),sizeof(word));
 | 
						|
        symversec.SecOptions:=[oso_keep];
 | 
						|
        verdefsec:=TElfObjSection.create_ext(internalObjData,'.gnu.version_d',
 | 
						|
          SHT_GNU_VERDEF,SHF_ALLOC,sizeof(pint),0);
 | 
						|
        verdefsec.SecOptions:=[oso_keep];
 | 
						|
        verneedsec:=TElfObjSection.create_ext(internalObjData,'.gnu.version_r',
 | 
						|
          SHT_GNU_VERNEED,SHF_ALLOC,sizeof(pint),0);
 | 
						|
        verneedsec.SecOptions:=[oso_keep];
 | 
						|
        dyncopysyms:=TFPObjectList.Create(False);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    const
 | 
						|
      hashbuckets: array[0..15] of longint=(
 | 
						|
        1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, 2053, 4099, 8209,
 | 
						|
        16411, 32771);
 | 
						|
 | 
						|
{$push}{$r-,q-}
 | 
						|
    function elfhash(const name:string):longword;
 | 
						|
      var
 | 
						|
        g: longword;
 | 
						|
        i: longint;
 | 
						|
      begin
 | 
						|
        result:=0;
 | 
						|
        for i:=1 to length(name) do
 | 
						|
        begin
 | 
						|
          result:=(result shl 4)+ord(name[i]);
 | 
						|
          g:=result and $F0000000;
 | 
						|
          if g>0 then
 | 
						|
            result:=result xor (g shr 24);
 | 
						|
          result:=result and (not g);
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
{$pop}
 | 
						|
 | 
						|
    procedure TElfExeOutput.WriteDynamicSymbolsHash;
 | 
						|
      var
 | 
						|
        nchains,nbuckets: longint;
 | 
						|
        i,j: longint;
 | 
						|
        hashdata: plongint;
 | 
						|
        sym: TExeSymbol;
 | 
						|
      begin
 | 
						|
        dynsymnames:=AllocMem(dynsymlist.count*sizeof(longword));
 | 
						|
        nchains:=dynsymlist.Count+1;
 | 
						|
        { determine suitable bucket count }
 | 
						|
        i:=high(hashbuckets);
 | 
						|
        while (i>=0) and (nchains<hashbuckets[i]) do
 | 
						|
          dec(i);
 | 
						|
        nbuckets:=hashbuckets[i];
 | 
						|
 | 
						|
        hashdata:=AllocMem((2+nchains+nbuckets)*sizeof(longint));
 | 
						|
        hashdata[0]:=nbuckets;
 | 
						|
        hashdata[1]:=nchains;
 | 
						|
        { The contents of .dynsym can be written only after mempos pass
 | 
						|
          because it needs valid symbol virtual addresses and section indices.
 | 
						|
          Here we preset .dynsym size and write names, in order to get
 | 
						|
          correct size of .dynstr section. }
 | 
						|
        dynsymtable.size:=(dynsymlist.count+1)*sizeof(TElfsymbol);
 | 
						|
        for i:=0 to dynsymlist.Count-1 do
 | 
						|
          begin
 | 
						|
            sym:=TExeSymbol(dynsymlist[i]);
 | 
						|
            dynsymnames[i]:=dynsymtable.fstrsec.writestr(sym.objsymbol.name);
 | 
						|
            j:=(elfhash(sym.objsymbol.name) mod nbuckets)+2;
 | 
						|
 | 
						|
            while hashdata[j]<>0 do
 | 
						|
              j:=2+nbuckets+hashdata[j];
 | 
						|
            hashdata[j]:=i+1;
 | 
						|
          end;
 | 
						|
        if source_info.endian<>target_info.endian then
 | 
						|
          for i:=0 to nchains+nbuckets+1 do
 | 
						|
            hashdata[i]:=swapendian(hashdata[i]);
 | 
						|
        hashobjsec.write(hashdata^,(2+nchains+nbuckets)*sizeof(longint));
 | 
						|
        freemem(hashdata);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.WriteVersionSections;
 | 
						|
      var
 | 
						|
        i,j: longint;
 | 
						|
        idx,auxidx: longword;
 | 
						|
        exesym: TExeSymbol;
 | 
						|
        dynobj: TElfDynamicObjData;
 | 
						|
        ver: TElfVersionDef;
 | 
						|
        vn: TElfverneed;
 | 
						|
        vna: TElfvernaux;
 | 
						|
        symversions: pword;
 | 
						|
      begin
 | 
						|
        symversions:=AllocMem((dynsymlist.count+1)*sizeof(word));
 | 
						|
        { Assign version indices }
 | 
						|
        idx:=VER_NDX_GLOBAL+1;
 | 
						|
        for i:=0 to dynsymlist.count-1 do
 | 
						|
          begin
 | 
						|
            exesym:=TExeSymbol(dynsymlist[i]);
 | 
						|
            if (exesym.objsymbol.indsymbol is TVersionedObjSymbol) then
 | 
						|
              ver:=TVersionedObjSymbol(exesym.objsymbol.indsymbol).version
 | 
						|
            else
 | 
						|
              ver:=nil;
 | 
						|
            if assigned(ver) then
 | 
						|
              begin
 | 
						|
                if ver.index=0 then
 | 
						|
                  begin
 | 
						|
                    ver.index:=idx;
 | 
						|
                    inc(idx);
 | 
						|
                  end;
 | 
						|
                symversions[i+1]:=ver.index;
 | 
						|
              end
 | 
						|
            else if exesym.state in [symstate_undefined,symstate_undefweak] then
 | 
						|
              symversions[i+1]:=VER_NDX_LOCAL
 | 
						|
            else
 | 
						|
              symversions[i+1]:=VER_NDX_GLOBAL;
 | 
						|
          end;
 | 
						|
 | 
						|
        { Count entries to be written }
 | 
						|
        verneedcount:=0;
 | 
						|
        for i:=0 to neededlist.count-1 do
 | 
						|
          begin
 | 
						|
            dynobj:=TElfDynamicObjData(neededlist[i]);
 | 
						|
            dynobj.vernaux_count:=0;
 | 
						|
            for j:=2 to dynobj.versiondefs.count-1 do
 | 
						|
              begin
 | 
						|
                ver:=TElfVersionDef(dynobj.versiondefs[j]);
 | 
						|
                if ver.index>VER_NDX_GLOBAL then
 | 
						|
                  inc(dynobj.vernaux_count);
 | 
						|
              end;
 | 
						|
            if (dynobj.vernaux_count>0) then
 | 
						|
              inc(verneedcount);
 | 
						|
          end;
 | 
						|
 | 
						|
        { Now write }
 | 
						|
        idx:=0;
 | 
						|
        for i:=0 to neededlist.count-1 do
 | 
						|
          begin
 | 
						|
            dynobj:=TElfDynamicObjData(neededlist[i]);
 | 
						|
            if dynobj.vernaux_count=0 then
 | 
						|
              continue;
 | 
						|
            inc(idx);
 | 
						|
            vn.vn_version:=VER_NEED_CURRENT;
 | 
						|
            vn.vn_cnt:=dynobj.vernaux_count;
 | 
						|
            vn.vn_file:=dynobj.soname_strofs;
 | 
						|
            vn.vn_aux:=sizeof(TElfverneed);
 | 
						|
            vn.vn_next:=ord(idx<verneedcount)*(sizeof(TElfverneed)+vn.vn_cnt*sizeof(TElfvernaux));
 | 
						|
            MaybeSwapElfverneed(vn);
 | 
						|
            verneedsec.write(vn,sizeof(TElfverneed));
 | 
						|
 | 
						|
            auxidx:=0;
 | 
						|
            for j:=2 to dynobj.versiondefs.count-1 do
 | 
						|
              begin
 | 
						|
                ver:=TElfVersionDef(dynobj.versiondefs[j]);
 | 
						|
                if ver.index<=VER_NDX_GLOBAL then
 | 
						|
                  continue;
 | 
						|
                inc(auxidx);
 | 
						|
                vna.vna_hash:=elfhash(ver.name);
 | 
						|
                vna.vna_flags:=0;   { BFD copies this from verdef.vd_flags?? }
 | 
						|
                vna.vna_other:=ver.index;
 | 
						|
                vna.vna_name:=dynsymtable.fstrsec.writestr(ver.name);
 | 
						|
                vna.vna_next:=ord(auxidx<dynobj.vernaux_count)*sizeof(TElfvernaux);
 | 
						|
                MaybeSwapElfvernaux(vna);
 | 
						|
                verneedsec.write(vna,sizeof(TElfvernaux));
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
        TElfExeSection(verneedsec.ExeSection).shinfo:=verneedcount;
 | 
						|
 | 
						|
        { If there are no needed versions, .gnu.version section is not needed }
 | 
						|
        if verneedcount>0 then
 | 
						|
          begin
 | 
						|
            if source_info.endian<>target_info.endian then
 | 
						|
              for i:=0 to dynsymlist.count+1 do
 | 
						|
                symversions[i]:=swapendian(symversions[i]);
 | 
						|
            symversec.write(symversions^,(dynsymlist.count+1)*sizeof(word));
 | 
						|
          end;
 | 
						|
        FreeMem(symversions);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.WriteDynRelocEntry(dataofs:aword;typ:byte;symidx:aword;addend:aword);
 | 
						|
      var
 | 
						|
        rel:telfreloc;
 | 
						|
      begin
 | 
						|
        rel.address:=dataofs;
 | 
						|
        rel.info:=ELF_R_INFO(symidx,typ);
 | 
						|
{$push}{$r-}
 | 
						|
        rel.addend:=addend;
 | 
						|
{$pop}
 | 
						|
        MaybeSwapElfReloc(rel);
 | 
						|
        dynrelocsec.write(rel,dynrelocsec.shentsize);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.WriteDynTag(aTag:longword;aValue:longword);
 | 
						|
      var
 | 
						|
        d: TElfDyn;
 | 
						|
      begin
 | 
						|
        d.d_tag:=aTag;
 | 
						|
        d.d_val:=aValue;
 | 
						|
        MaybeSwapElfDyn(d);
 | 
						|
        dynamicsec.write(d,sizeof(TElfDyn));
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.WriteDynTag(aTag:longword;aSection:TObjSection;aOffs:aword);
 | 
						|
      var
 | 
						|
        d: TElfDyn;
 | 
						|
      begin
 | 
						|
        d.d_tag:=aTag;
 | 
						|
        if source_info.endian<>target_info.endian then
 | 
						|
          d.d_tag:=swapendian(d.d_tag);
 | 
						|
        dynamicsec.write(d.d_tag,sizeof(d.d_tag));
 | 
						|
        { TODO: ignores endianness! }
 | 
						|
        dynamicsec.writeReloc_internal(aSection,aOffs,sizeof(d.d_ptr),RELOC_ABSOLUTE);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.WriteTargetDynamicTags;
 | 
						|
      begin
 | 
						|
        { to be overridden by CPU-specific descendants }
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.WriteDynamicTags;
 | 
						|
      var
 | 
						|
        s: aword;
 | 
						|
        i: longint;
 | 
						|
        sym: TExeSymbol;
 | 
						|
        hs:string;
 | 
						|
        dynobj: TElfDynamicObjData;
 | 
						|
      begin
 | 
						|
        for i:=0 to neededlist.Count-1 do
 | 
						|
          begin
 | 
						|
            dynobj:=TElfDynamicObjData(neededlist[i]);
 | 
						|
            s:=dynsymtable.fstrsec.writestr(dynobj.name);
 | 
						|
            dynobj.soname_strofs:=s;
 | 
						|
            WriteDynTag(DT_NEEDED,s);
 | 
						|
          end;
 | 
						|
 | 
						|
        if IsSharedLibrary then
 | 
						|
          begin
 | 
						|
            s:=dynsymtable.fstrsec.writestr(ExtractFileName(current_module.sharedlibfilename));
 | 
						|
            WriteDynTag(DT_SONAME,s);
 | 
						|
            { TODO: names hardcoded here }
 | 
						|
            sym:=TExeSymbol(ExeSymbolList.Find('FPC_SHARED_LIB_START'));
 | 
						|
            if assigned(sym) then
 | 
						|
              WriteDynTag(DT_INIT,sym.objsymbol.objsection,sym.objsymbol.offset);
 | 
						|
            sym:=TExeSymbol(ExeSymbolList.Find('FPC_LIB_EXIT'));
 | 
						|
            if assigned(sym) then
 | 
						|
              WriteDynTag(DT_FINI,sym.objsymbol.objsection,sym.objsymbol.offset);
 | 
						|
          end;
 | 
						|
 | 
						|
        { TODO: we need a dedicated parameter to pass runpath, instead of this hack
 | 
						|
          (-Xr is a different thing, it passes "-rpath-link"). }
 | 
						|
        if (ParaLinkOptions<>'') then
 | 
						|
          begin
 | 
						|
            hs:=ParaLinkOptions;
 | 
						|
            while (hs<>'') do
 | 
						|
              begin
 | 
						|
                if (GetToken(hs,' ')='-rpath') then
 | 
						|
                  begin
 | 
						|
                    s:=dynsymtable.fstrsec.writestr(GetToken(hs,' '));
 | 
						|
                    WriteDynTag(DT_RPATH,s);
 | 
						|
                  end;
 | 
						|
              end;
 | 
						|
          end;
 | 
						|
 | 
						|
        writeDynTag(DT_HASH,hashobjsec);
 | 
						|
        writeDynTag(DT_STRTAB,dynsymtable.fstrsec);
 | 
						|
        writeDynTag(DT_SYMTAB,dynsymtable);
 | 
						|
 | 
						|
        writeDynTag(DT_SYMENT,sizeof(TElfSymbol));
 | 
						|
 | 
						|
        if Assigned(gotpltobjsec) then
 | 
						|
          writeDynTag(DT_PLTGOT,gotpltobjsec);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    const
 | 
						|
      pltreltags: array[boolean] of longword=(DT_REL,DT_RELA);
 | 
						|
      relsztags:  array[boolean] of longword=(DT_RELSZ,DT_RELASZ);
 | 
						|
      relenttags: array[boolean] of longword=(DT_RELENT,DT_RELAENT);
 | 
						|
      relcnttags: array[boolean] of longword=(DT_RELCOUNT,DT_RELACOUNT);
 | 
						|
 | 
						|
    procedure TElfExeOutput.FinishDynamicTags;
 | 
						|
      var
 | 
						|
        rela: boolean;
 | 
						|
      begin
 | 
						|
        if assigned(dynsymtable) then
 | 
						|
          writeDynTag(DT_STRSZ,dynsymtable.fstrsec.size);
 | 
						|
 | 
						|
        if hastextrelocs then
 | 
						|
          writeDynTag(DT_TEXTREL,0);
 | 
						|
 | 
						|
        if Assigned(pltrelocsec) and (pltrelocsec.size>0) then
 | 
						|
          begin
 | 
						|
            writeDynTag(DT_PLTRELSZ,pltrelocsec.Size);
 | 
						|
            writeDynTag(DT_PLTREL,pltreltags[pltrelocsec.shtype=SHT_RELA]);
 | 
						|
            writeDynTag(DT_JMPREL,pltrelocsec);
 | 
						|
          end;
 | 
						|
 | 
						|
        if Assigned(dynrelocsec) and (dynrelocsec.size>0) then
 | 
						|
          begin
 | 
						|
            rela:=(dynrelocsec.shtype=SHT_RELA);
 | 
						|
            writeDynTag(pltreltags[rela],dynrelocsec);
 | 
						|
            writeDynTag(relsztags[rela],dynrelocsec.Size);
 | 
						|
            writeDynTag(relenttags[rela],dynrelocsec.shentsize);
 | 
						|
{$ifndef MIPS}
 | 
						|
            if (relative_reloc_count>0) then
 | 
						|
              writeDynTag(relcnttags[rela],relative_reloc_count);
 | 
						|
{$endif MIPS}
 | 
						|
          end;
 | 
						|
 | 
						|
        WriteTargetDynamicTags;
 | 
						|
 | 
						|
        if (verdefcount>0) or (verneedcount>0) then
 | 
						|
          begin
 | 
						|
            if (verdefcount>0) then
 | 
						|
              begin
 | 
						|
                writeDynTag(DT_VERDEF,verdefsec);
 | 
						|
                writeDynTag(DT_VERDEFNUM,verdefcount);
 | 
						|
              end;
 | 
						|
            if (verneedcount>0) then
 | 
						|
              begin
 | 
						|
                writeDynTag(DT_VERNEED,verneedsec);
 | 
						|
                writeDynTag(DT_VERNEEDNUM,verneedcount);
 | 
						|
              end;
 | 
						|
            writeDynTag(DT_VERSYM,symversec);
 | 
						|
          end;
 | 
						|
        writeDynTag(DT_NULL,0);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.CreatePLT;
 | 
						|
      var
 | 
						|
        reloc: TObjRelocation;
 | 
						|
      begin
 | 
						|
        pltobjsec:=TElfObjSection.create_ext(internalObjData,'.plt',
 | 
						|
          SHT_PROGBITS,SHF_ALLOC or SHF_EXECINSTR,4,16);
 | 
						|
        pltobjsec.SecOptions:=[oso_keep,oso_plt];
 | 
						|
 | 
						|
        pltrelocsec:=TElfObjSection.create_reloc(internalObjData,'.plt',true);
 | 
						|
        pltrelocsec.SecOptions:=[oso_keep];
 | 
						|
 | 
						|
        ipltrelocsec:=TElfObjSection.create_reloc(internalObjData,'.iplt',true);
 | 
						|
        ipltrelocsec.SecOptions:=[oso_keep];
 | 
						|
 | 
						|
        { reference .dynamic from .got.plt, this isn't necessary if linking statically }
 | 
						|
        { TODO: maybe move writing initial .got.plt entries here completely
 | 
						|
          (needs testing --- GOT symbol may get lost if .got.plt is empty)}
 | 
						|
        if dynamiclink then
 | 
						|
          begin
 | 
						|
            reloc:=TObjRelocation.CreateSection(0,dynamicsec,RELOC_ABSOLUTE);
 | 
						|
            reloc.size:=sizeof(pint);
 | 
						|
            gotpltobjsec.ObjRelocations.Add(reloc);
 | 
						|
          end;
 | 
						|
 | 
						|
        { Initial PLT entry, CPU-specific }
 | 
						|
        WriteFirstPLTEntry;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.WritePLTEntry(exesym:TExeSymbol);
 | 
						|
      begin
 | 
						|
        // must be implemented by CPU-specific descendant
 | 
						|
        InternalError(2012092102);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.WriteIndirectPLTEntry(exesym:TExeSymbol);
 | 
						|
      begin
 | 
						|
        // must be implemented by CPU-specific descendant
 | 
						|
        InternalError(2012092101);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    function TElfExeOutput.WriteData:boolean;
 | 
						|
      begin
 | 
						|
        WriteHeader;
 | 
						|
        segmentlist.ForEachCall(@segment_write_header,nil);
 | 
						|
        WriteExeSectionContent;
 | 
						|
        FWriter.WriteZeros(sizeof(TElfsechdr));
 | 
						|
        ExeSectionList.ForEachCall(@exesection_write_header,nil);
 | 
						|
        result:=true;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.GenerateLibraryImports(ImportLibraryList:TFPHashObjectList);
 | 
						|
      var
 | 
						|
        exportlist: TCmdStrList;
 | 
						|
        sym: TExeSymbol;
 | 
						|
      begin
 | 
						|
        AllowUndefinedSymbols:=IsSharedLibrary;
 | 
						|
        { add exported symbols to dynamic list }
 | 
						|
        exportlist:=texportlibunix(exportlib).exportedsymnames;
 | 
						|
        if not exportlist.empty then
 | 
						|
          repeat
 | 
						|
            sym:=TExeSymbol(ExeSymbolList.Find(exportlist.getfirst));
 | 
						|
            if assigned(sym) then
 | 
						|
              begin
 | 
						|
                if assigned(sym.objsymbol.objsection) then
 | 
						|
                  sym.objsymbol.objsection.SecOptions:=[oso_keep];
 | 
						|
                sym.dynindex:=dynsymlist.add(sym)+1
 | 
						|
              end
 | 
						|
            else
 | 
						|
              InternalError(2012071801);
 | 
						|
          until exportlist.empty;
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.ReportNonDSOReloc(reltyp:byte;objsec:TObjSection;ObjReloc:TObjRelocation);
 | 
						|
      begin
 | 
						|
        { TODO: include objsec properties into message }
 | 
						|
        Comment(v_error,'Relocation '+ElfTarget.RelocName(reltyp)+' against '''+objreloc.TargetName+''' cannot be used when linking a shared object; recompile with -Cg');
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
    procedure TElfExeOutput.ReportRelocOverflow(reltyp:byte;objsec:TObjSection;ObjReloc:TObjRelocation);
 | 
						|
      begin
 | 
						|
        { TODO: include objsec properties into message }
 | 
						|
        Comment(v_error,'Relocation truncated to fit: '+ElfTarget.RelocName(reltyp)+' against '''+objreloc.TargetName+'''');
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
{****************************************************************************
 | 
						|
                               TElfExeSection
 | 
						|
****************************************************************************}
 | 
						|
 | 
						|
    procedure TElfExeSection.AddObjSection(objsec:TObjSection;ignoreprops:boolean);
 | 
						|
      begin
 | 
						|
        inherited AddObjSection(objsec,ignoreprops);
 | 
						|
        if ignoreprops then
 | 
						|
          exit;
 | 
						|
        if (shtype=SHT_NULL) then
 | 
						|
        begin
 | 
						|
          shtype:=TElfObjSection(objsec).shtype;
 | 
						|
          shflags:=TElfObjSection(objsec).shflags;
 | 
						|
          shentsize:=TElfObjSection(objsec).shentsize;
 | 
						|
        end;
 | 
						|
      end;
 | 
						|
 | 
						|
{****************************************************************************
 | 
						|
                                TElfSegment
 | 
						|
****************************************************************************}
 | 
						|
 | 
						|
    constructor TElfSegment.Create(atype,aflags,aalign:longword);
 | 
						|
      begin
 | 
						|
        ptype:=atype;
 | 
						|
        pflags:=aflags;
 | 
						|
        align:=aalign;
 | 
						|
        FSectionList:=TFPObjectList.Create(false);
 | 
						|
      end;
 | 
						|
 | 
						|
    destructor TElfSegment.Destroy;
 | 
						|
      begin
 | 
						|
        FSectionList.Free;
 | 
						|
        inherited Destroy;
 | 
						|
      end;
 | 
						|
 | 
						|
    procedure TElfSegment.Add(exesec:TExeSection);
 | 
						|
      begin
 | 
						|
        FSectionList.Add(exesec);
 | 
						|
      end;
 | 
						|
 | 
						|
 | 
						|
end.
 |