From 277200e7ae4fdcb2dbc90be2f5879a3cfb2b1e04 Mon Sep 17 00:00:00 2001 From: sergei Date: Thu, 8 Nov 2012 11:10:01 +0000 Subject: [PATCH] + ELF linker: Support writing RELATIVE dynamic relocations ahead of the rest, and their number in DT_REL[A]COUNT dynamic tag (still needs changes in CPU-specific code to function properly). * TElfObjInput.LoadSymbols: ignore STT_SECTION symbols for sections that were ignored in LoadSections(). * TElfObjInput: changed symtabndx (index of .symtab/.dynsym section) into field and its type to unsigned. git-svn-id: trunk@22951 - --- compiler/ogelf.pas | 59 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/compiler/ogelf.pas b/compiler/ogelf.pas index 73776e6c20..84086a63e6 100644 --- a/compiler/ogelf.pas +++ b/compiler/ogelf.pas @@ -118,6 +118,7 @@ interface shentsize: longword; shoffset: aword; shstrndx: longword; + symtabndx: longword; shstrtab: PChar; strtab: PChar; shstrtablen: longword; @@ -216,7 +217,9 @@ interface pltrelocsec, ipltrelocsec, dynrelocsec: TElfObjSection; + dynreloclist: TFPObjectList; tlsseg: TElfSegment; + relative_reloc_count: longint; procedure WriteDynRelocEntry(dataofs:aword;typ:byte;symidx:aword;addend:aword); procedure WriteFirstPLTEntry;virtual;abstract; procedure WritePLTEntry(exesym:TExeSymbol);virtual; @@ -315,6 +318,7 @@ implementation {$endif x86_64} SHN_UNDEF = 0; + SHN_LORESERVE = $FF00; SHN_ABS = $fff1; SHN_COMMON = $fff2; @@ -1568,16 +1572,8 @@ implementation Continue else if sym.st_shndx=SHN_COMMON then bind:=AB_COMMON - else if (sym.st_shndx>=nsects) or - ( - (sym.st_shndx>0) and - (FSecTbl[sym.st_shndx].sec=nil) and - (not dynobj) - ) then - begin - writeln(objdata.name,' ',i); - InternalError(2012060206) - end + else if (sym.st_shndx>=nsects) then + InternalError(2012060206) else case (sym.st_info shr 4) of STB_LOCAL: @@ -1593,6 +1589,19 @@ implementation 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_shndxsymsectypes[dynobj]) then @@ -1880,6 +1889,9 @@ implementation break; end; + if symtabndx=0 then + InternalError(2012110706); + if dynobj then begin { Locate .dynamic and version sections. Expect a single one of a kind. } @@ -2031,6 +2043,7 @@ implementation neededlist.Free; segmentlist.Free; dynsymlist.Free; + dynreloclist.Free; if assigned(dynsymnames) then FreeMem(dynsymnames); inherited Destroy; @@ -2629,8 +2642,25 @@ implementation i,j: longint; exesec: TExeSection; seg: TElfSegment; + objreloc: TObjRelocation; begin gotwritten:=true; + { If target does not support sorted relocations, it is expected to write the + entire .rel[a].dyn section during FixupRelocations. Otherwise, only RELATIVE ones + should be written, space for non-relative relocations should remain. } + if assigned(dynrelocsec) and (relative_reloc_count>0) then + begin + 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); @@ -2743,6 +2773,8 @@ implementation dynrelocsec:=TElfObjSection.create_reloc(internalObjData,'.dyn',true); dynrelocsec.SecOptions:=[oso_keep]; + + dynreloclist:=TFPObjectList.Create(true); end; @@ -2902,6 +2934,7 @@ implementation 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; begin @@ -2924,6 +2957,8 @@ implementation writeDynTag(relsztags[relocs_use_addend],dynrelocsec.Size); writeDynTag(relenttags[relocs_use_addend],dynrelocsec.shentsize); end; + if (relative_reloc_count>0) then + writeDynTag(relcnttags[relocs_use_addend],relative_reloc_count); writeDynTag(DT_NULL,0); end;