mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-06-05 18:18:26 +02:00
+ MIPS: doing progress with linker, implemented processing of local symbols in PIC code and stuff needed to link shared libraries.
git-svn-id: trunk@23690 -
This commit is contained in:
parent
268b2d56d7
commit
6fcd9979dd
@ -39,6 +39,10 @@ implementation
|
||||
gnugpsym: TObjSymbol;
|
||||
dt_gotsym_value: longint;
|
||||
dt_local_gotno_value: longint;
|
||||
dt_local_gotno_offset: aword;
|
||||
local_got_relocs: TFPObjectList;
|
||||
local_got_slots: TFPHashObjectList;
|
||||
got_content: array of pint;
|
||||
procedure MaybeWriteGOTEntry(reltyp:byte;relocval:aint;objsym:TObjSymbol);
|
||||
protected
|
||||
procedure PrepareGOT;override;
|
||||
@ -51,8 +55,11 @@ implementation
|
||||
// procedure WriteIndirectPLTEntry(exesym:TExeSymbol);override;
|
||||
procedure GOTRelocPass1(objsec:TObjSection;var idx:longint);override;
|
||||
procedure DoRelocationFixup(objsec:TObjSection);override;
|
||||
procedure Do_Mempos;override;
|
||||
public
|
||||
procedure DataPos_Start;override;
|
||||
constructor Create;override;
|
||||
destructor Destroy;override;
|
||||
procedure FixupRelocations;override;
|
||||
end;
|
||||
|
||||
const
|
||||
@ -176,6 +183,22 @@ implementation
|
||||
TElfExeOutputMIPS
|
||||
*****************************************************************************}
|
||||
|
||||
constructor TElfExeOutputMIPS.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
local_got_relocs:=TFPObjectList.Create(False);
|
||||
local_got_slots:=TFPHashObjectList.Create(True);
|
||||
end;
|
||||
|
||||
|
||||
destructor TElfExeOutputMIPS.Destroy;
|
||||
begin
|
||||
local_got_slots.Free;
|
||||
local_got_relocs.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
|
||||
procedure TElfExeOutputMIPS.CreateGOTSection;
|
||||
var
|
||||
tmp: longword;
|
||||
@ -222,6 +245,7 @@ implementation
|
||||
writeDynTag(DT_MIPS_BASE_ADDRESS,0)
|
||||
else
|
||||
writeDynTag(DT_MIPS_BASE_ADDRESS,ElfTarget.exe_image_base);
|
||||
dt_local_gotno_offset:=dynamicsec.size;
|
||||
writeDynTag(DT_MIPS_LOCAL_GOTNO,dt_local_gotno_value);
|
||||
writeDynTag(DT_MIPS_SYMTABNO,dynsymlist.count+1);
|
||||
{ ABI says: "Index of first external dynamic symbol not referenced locally" }
|
||||
@ -248,16 +272,8 @@ implementation
|
||||
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=nil) then
|
||||
InternalError(2013030406);
|
||||
if exesym.GotOffset>0 then
|
||||
exit;
|
||||
make_dynamic_if_undefweak(exesym);
|
||||
@ -284,14 +300,32 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
function address_ascending(p1,p2:pointer):longint;
|
||||
var
|
||||
reloc1: TObjRelocation absolute p1;
|
||||
reloc2: TObjRelocation absolute p2;
|
||||
begin
|
||||
result:=(reloc1.symbol.address+reloc1.orgsize)-(reloc2.symbol.address+reloc2.orgsize);
|
||||
end;
|
||||
|
||||
|
||||
procedure TElfExeOutputMIPS.PrepareGOT;
|
||||
var
|
||||
i: longint;
|
||||
exesym: TExeSymbol;
|
||||
begin
|
||||
inherited PrepareGOT;
|
||||
{ !! maybe incorrect, where do 'unmapped globals' belong? }
|
||||
dt_local_gotno_value:=gotobjsec.size div sizeof(pint);
|
||||
|
||||
if not dynamiclink then
|
||||
exit;
|
||||
{ make room for first R_MIPS_NONE entry }
|
||||
if dynrelsize>0 then
|
||||
begin
|
||||
dynrelocsec.alloc(dynrelocsec.shentsize);
|
||||
inc(dynrelsize,dynrelocsec.shentsize);
|
||||
end;
|
||||
dynsymlist.sort(@put_externals_last);
|
||||
{ reindex, as sorting could changed the order }
|
||||
for i:=0 to dynsymlist.count-1 do
|
||||
@ -306,8 +340,6 @@ implementation
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
{ !! maybe incorrect, where do 'unmapped globals' belong? }
|
||||
dt_local_gotno_value:=gotobjsec.size div sizeof(pint);
|
||||
|
||||
{ actually allocate GOT slots for imported symbols }
|
||||
for i:=dt_gotsym_value to dynsymlist.count-1 do
|
||||
@ -320,25 +352,119 @@ implementation
|
||||
end;
|
||||
|
||||
|
||||
procedure TElfExeOutputMIPS.DataPos_Start;
|
||||
procedure TElfExeOutputMIPS.Do_Mempos;
|
||||
var
|
||||
i:longint;
|
||||
objrel:TObjRelocation;
|
||||
addr,page:aword;
|
||||
numpages,tmp:longint;
|
||||
objsym:TObjSymbol;
|
||||
exesym:TExeSymbol;
|
||||
got_local_area_start:aword;
|
||||
begin
|
||||
inherited Do_Mempos;
|
||||
{ determine required amount of 64k page entries }
|
||||
local_got_relocs.Sort(@address_ascending);
|
||||
numpages:=0;
|
||||
page:=high(aword);
|
||||
for i:=0 to local_got_relocs.count-1 do
|
||||
begin
|
||||
objrel:=TObjRelocation(local_got_relocs[i]);
|
||||
addr:=objrel.symbol.address+objrel.orgsize;
|
||||
addr:=addr-smallint(addr);
|
||||
if (page<>addr shr 16) then
|
||||
inc(numpages);
|
||||
page:=addr shr 16;
|
||||
end;
|
||||
|
||||
if (numpages=0) then
|
||||
exit;
|
||||
|
||||
{ An additional page may be consumed when we add slots to GOT }
|
||||
inc(numpages);
|
||||
|
||||
{ Make space in GOT }
|
||||
got_local_area_start:=dt_local_gotno_value;
|
||||
inc(gotsize,numpages*sizeof(pint));
|
||||
gotobjsec.alloc(numpages*sizeof(pint));
|
||||
|
||||
{ Redo layout }
|
||||
inherited Do_Mempos;
|
||||
|
||||
{ Now assign GOT offsets to local slots }
|
||||
SetLength(got_content,numpages);
|
||||
page:=high(aword);
|
||||
tmp:=-1;
|
||||
objsym:=nil;
|
||||
for i:=0 to local_got_relocs.count-1 do
|
||||
begin
|
||||
objrel:=TObjRelocation(local_got_relocs[i]);
|
||||
addr:=objrel.symbol.address+objrel.orgsize;
|
||||
{ the contents of slot }
|
||||
addr:=addr-smallint(addr);
|
||||
if (page<>addr) then
|
||||
begin
|
||||
Inc(tmp);
|
||||
if (tmp>=numpages) then
|
||||
InternalError(2013030402);
|
||||
{ replace relocation symbol with one pointing to GOT slot }
|
||||
objsym:=TObjSymbol.Create(local_got_slots,hexstr(addr,8));
|
||||
objsym.offset:=(got_local_area_start+tmp+1)*sizeof(pint);
|
||||
objsym.bind:=AB_LOCAL;
|
||||
if (source_info.endian=target_info.endian) then
|
||||
got_content[tmp]:=addr
|
||||
else
|
||||
got_content[tmp]:=swapendian(addr);
|
||||
page:=addr;
|
||||
end;
|
||||
objrel.symbol:=objsym;
|
||||
end;
|
||||
|
||||
if dynamiclink then
|
||||
begin
|
||||
{ Patch DT_LOCAL_GOTNO value }
|
||||
if (dt_local_gotno_offset=0) then
|
||||
InternalError(2013030401);
|
||||
i:=dynamicsec.size;
|
||||
dynamicsec.Data.Seek(dt_local_gotno_offset);
|
||||
writeDynTag(DT_MIPS_LOCAL_GOTNO,dt_local_gotno_value+numpages);
|
||||
dynamicsec.size:=i;
|
||||
|
||||
{ Increase gotoffset of exesymbols that come after dt_gotsym }
|
||||
for i:=dt_gotsym_value to dynsymlist.count-1 do
|
||||
begin
|
||||
exesym:=TExeSymbol(dynsymlist[i]);
|
||||
exesym.GotOffset:=exesym.GotOffset+(numpages*sizeof(pint));
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure TElfExeOutputMIPS.FixupRelocations;
|
||||
begin
|
||||
if dynrelsize>0 then
|
||||
WriteDynRelocEntry(0,R_MIPS_NONE,0,0);
|
||||
|
||||
inherited FixupRelocations;
|
||||
{ Since we omit GOT slots for imported symbols during inherited PrepareGOT, they don't
|
||||
get written in ResolveRelocations either. This must be compensated here.
|
||||
Or better override ResolveRelocations and handle there. }
|
||||
get written in FixupRelocations either. This must be compensated here. }
|
||||
gotobjsec.write(got_content[0],length(got_content)*sizeof(pint));
|
||||
|
||||
{ TODO: shouldn't be zeroes, but address of stubs if address taken, etc. }
|
||||
gotobjsec.writeZeros(gotsize-gotobjsec.size);
|
||||
inherited DataPos_Start;
|
||||
end;
|
||||
|
||||
procedure TElfExeOutputMIPS.MaybeWriteGOTEntry(reltyp:byte;relocval:aint;objsym:TObjSymbol);
|
||||
var
|
||||
gotoff:aword;
|
||||
begin
|
||||
if (objsym.bind=AB_LOCAL) then
|
||||
InternalError(2013030403);
|
||||
gotoff:=objsym.exesymbol.gotoffset;
|
||||
if gotoff=0 then
|
||||
InternalError(2012060902);
|
||||
|
||||
{ the GOT slot itself, and a dynamic relocation for it }
|
||||
{ On MIPS, GOT does not need dynamic relocations }
|
||||
if gotoff=gotobjsec.Data.size+sizeof(pint) then
|
||||
begin
|
||||
if source_info.endian<>target_info.endian then
|
||||
@ -350,7 +476,12 @@ implementation
|
||||
procedure TElfExeOutputMIPS.GOTRelocPass1(objsec:TObjSection;var idx:longint);
|
||||
var
|
||||
objreloc:TObjRelocation;
|
||||
lowreloc:TObjRelocation;
|
||||
reltyp:byte;
|
||||
externsym:boolean;
|
||||
found:boolean;
|
||||
i:longint;
|
||||
lopart,hipart:longword;
|
||||
begin
|
||||
objreloc:=TObjRelocation(objsec.ObjRelocations[idx]);
|
||||
if (ObjReloc.flags and rf_raw)=0 then
|
||||
@ -359,11 +490,56 @@ implementation
|
||||
reltyp:=ObjReloc.ftype;
|
||||
|
||||
case reltyp of
|
||||
R_MIPS_32:
|
||||
begin
|
||||
externsym:=assigned(objreloc.symbol) and
|
||||
assigned(objreloc.symbol.exesymbol) and
|
||||
(objreloc.symbol.exesymbol.dynindex<>0);
|
||||
|
||||
if IsSharedLibrary then
|
||||
begin
|
||||
dynrelocsec.alloc(dynrelocsec.shentsize);
|
||||
objreloc.flags:=objreloc.flags or rf_dynamic;
|
||||
if (not externsym) then
|
||||
Inc(relative_reloc_count);
|
||||
end
|
||||
end;
|
||||
|
||||
R_MIPS_CALL16,
|
||||
R_MIPS_GOT16:
|
||||
begin
|
||||
//TODO: GOT16 against local symbols need specialized handling
|
||||
AllocGOTSlot(objreloc.symbol);
|
||||
if objreloc.symbol.bind<>AB_LOCAL then
|
||||
AllocGOTSlot(objreloc.symbol)
|
||||
else
|
||||
begin
|
||||
{ Extract the addend, which is stored split between this relocation and
|
||||
the following (maybe not immediately) R_MIPS_LO16 one. }
|
||||
found:=false;
|
||||
for i:=idx+1 to objsec.ObjRelocations.Count-1 do
|
||||
begin
|
||||
lowreloc:=TObjRelocation(objsec.ObjRelocations[i]);
|
||||
if (lowreloc.flags and rf_raw)=0 then
|
||||
InternalError(2013030101);
|
||||
if (lowreloc.ftype=R_MIPS_LO16) then
|
||||
begin;
|
||||
found:=true;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
if not found then
|
||||
InternalError(2013030102);
|
||||
objsec.Data.Seek(objreloc.DataOffset);
|
||||
objsec.Data.Read(hipart,sizeof(hipart));
|
||||
objsec.Data.Seek(lowreloc.DataOffset);
|
||||
objsec.Data.Read(lopart,sizeof(lopart));
|
||||
if (source_info.endian<>target_info.endian) then
|
||||
begin
|
||||
hipart:=swapendian(hipart);
|
||||
lopart:=swapendian(lopart);
|
||||
end;
|
||||
objreloc.orgsize:=(hipart shl 16)+SmallInt(lopart);
|
||||
local_got_relocs.add(objreloc);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
@ -450,19 +626,17 @@ implementation
|
||||
|
||||
R_MIPS_32:
|
||||
begin
|
||||
address:=address+relocval;
|
||||
if (objreloc.flags and rf_dynamic)<>0 then
|
||||
begin
|
||||
if (objreloc.symbol=nil) or
|
||||
(objreloc.symbol.exesymbol=nil) or
|
||||
(objreloc.symbol.exesymbol.dynindex=0) then
|
||||
begin
|
||||
end
|
||||
WriteDynRelocEntry(curloc,R_MIPS_REL32,0,address)
|
||||
else
|
||||
;
|
||||
end
|
||||
else
|
||||
address:=address+relocval;
|
||||
end;
|
||||
dynreloclist.add(TObjRelocation.CreateRaw(curloc,objreloc.symbol,R_MIPS_REL32));
|
||||
end;
|
||||
end;
|
||||
|
||||
R_MIPS_26:
|
||||
begin
|
||||
@ -486,6 +660,13 @@ implementation
|
||||
|
||||
R_MIPS_LO16:
|
||||
begin
|
||||
{ LO16 may be without pair, e.g. in following sequence:
|
||||
lui $v0, %hi(foo)
|
||||
lw $a0, %lo(foo)($v0)
|
||||
lw $a1, %lo(foo+4)($v0)
|
||||
}
|
||||
AHL_S:=SmallInt(address)+relocval;
|
||||
is_gp_disp:=false;
|
||||
while assigned(reloclist) do
|
||||
begin
|
||||
hr:=reloclist;
|
||||
@ -494,33 +675,57 @@ implementation
|
||||
// InternalError();
|
||||
{ _gp_disp and __gnu_local_gp magic }
|
||||
if assigned(hr^.objrel.symbol) and
|
||||
assigned(hr^.objrel.symbol.exesymbol) then
|
||||
(hr^.objrel.symbol.bind<>AB_LOCAL) then
|
||||
begin
|
||||
is_gp_disp:=(hr^.objrel.symbol.exesymbol.objsymbol=gpdispsym);
|
||||
if (hr^.objrel.symbol.exesymbol.objsymbol=gnugpsym) then
|
||||
relocval:=gotsymbol.address;
|
||||
end;
|
||||
|
||||
{ in case of _gp_disp, non-zero addend is not possible? }
|
||||
{ 4 must be added right here, so possible overflow in low half
|
||||
is propagated into high one (e.g if displacement is $37ffc,
|
||||
high part must be 4, not 3) }
|
||||
if is_gp_disp then
|
||||
relocval:=gotsymbol.address-curloc;
|
||||
relocval:=gotsymbol.address-curloc+4;
|
||||
AHL_S:=(hr^.addend shl 16)+SmallInt(address)+relocval;
|
||||
{ formula: ((AHL + S) – (short)(AHL + S)) >> 16 }
|
||||
tmp:=(hr^.addend and $FFFF0000) or ((AHL_S-SmallInt(AHL_S)) shr 16);
|
||||
|
||||
case hr^.objrel.ftype of
|
||||
|
||||
R_MIPS_HI16:
|
||||
tmp:=(AHL_S-SmallInt(AHL_S)) shr 16;
|
||||
|
||||
R_MIPS_GOT16:
|
||||
tmp:=-(gotsymbol.offset-(hr^.objrel.symbol.offset-sizeof(pint)));
|
||||
|
||||
else
|
||||
InternalError(2013030404);
|
||||
end;
|
||||
|
||||
tmp:=(hr^.addend and $FFFF0000) or (tmp and $FFFF);
|
||||
data.seek(hr^.objrel.dataoffset);
|
||||
if source_info.endian<>target_info.endian then
|
||||
tmp:=swapendian(tmp);
|
||||
data.Write(tmp,4);
|
||||
dispose(hr);
|
||||
end;
|
||||
if is_gp_disp then
|
||||
Inc(AHL_S,4);
|
||||
address:=(address and $FFFF0000) or (AHL_S and $FFFF);
|
||||
end;
|
||||
|
||||
R_MIPS_CALL16,
|
||||
R_MIPS_GOT16:
|
||||
begin
|
||||
//TODO: GOT16 relocations against local symbols need specialized handling
|
||||
{ GOT16 relocations against local symbols are followed by LO16 }
|
||||
if (objreloc.symbol.bind=AB_LOCAL) then
|
||||
begin
|
||||
new(hr);
|
||||
hr^.next:=reloclist;
|
||||
hr^.objrel:=objreloc;
|
||||
hr^.objsec:=objsec;
|
||||
hr^.addend:=address; //TODO: maybe it can be saved in objrel.orgsize field
|
||||
reloclist:=hr;
|
||||
continue;
|
||||
end;
|
||||
MaybeWriteGOTEntry(reltyp,relocval,objreloc.symbol);
|
||||
// !! this is correct only while _gp symbol is defined relative to .got !!
|
||||
relocval:=-(gotsymbol.offset-(objreloc.symbol.exesymbol.gotoffset-sizeof(pint)));
|
||||
|
@ -237,7 +237,6 @@ interface
|
||||
symversec,
|
||||
verdefsec,
|
||||
verneedsec,
|
||||
dynamicsec,
|
||||
hashobjsec: TElfObjSection;
|
||||
neededlist: TFPHashList;
|
||||
dyncopysyms: TFPObjectList;
|
||||
@ -262,6 +261,7 @@ interface
|
||||
hastextrelocs: boolean;
|
||||
gotsymbol: TObjSymbol;
|
||||
dynsymlist: TFPObjectList;
|
||||
dynamicsec,
|
||||
gotobjsec: TObjSection;
|
||||
dynbssobjsec,
|
||||
pltobjsec,
|
||||
@ -3021,8 +3021,10 @@ implementation
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user