mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-15 05:59:30 +02:00
* changed the Mach-O object writer to use symbols instead of section numbers
in the relocations (change the relocations to use "external reference" in Mach-O terminology), because initially section number-based relocations were not supported for AArch64 and later they were added but behave slightly differently from those on other platforms (or there's a bug in (some?) linker versions with them) (mantis #27531) o also add a dummy text section, since the assemblers also always do that o only use references to global symbols in the relocations, because when using local symbols in assembler code then for most architectures these must then be translated to section references (like the old code did), while for others they should remain symbols. For global symbols, the behaviour is the same everywhere git-svn-id: trunk@29999 -
This commit is contained in:
parent
5302024e25
commit
6149d37e2a
@ -183,6 +183,8 @@ const
|
||||
N_SECT = $e; // defined in section number n_sect
|
||||
N_PBUD = $c; // prebound undefined (defined in a dylib)
|
||||
N_INDR = $a; // indirect
|
||||
|
||||
NO_SECT = $0; // symbol is not in any section
|
||||
|
||||
//Relocations: masks for flag
|
||||
R_SYMBOLNUM_BE = $FFFFFF00;
|
||||
|
@ -17,10 +17,11 @@ type
|
||||
_TMachOSymbolTable_ = class(TMachOSymbolTable)
|
||||
protected
|
||||
function AddSymbol(aName : string; sect : byte; addr : longword;
|
||||
glob : boolean) : integer; override;
|
||||
glob, undef : boolean) : integer; override;
|
||||
protected
|
||||
public
|
||||
procedure WriteToStream(aStream : TStream); override;
|
||||
procedure SetSymbolOffset(symbolnum : integer; offset: longword); override;
|
||||
end;
|
||||
|
||||
_TMachOSubWriter_ = class(TAbstractMachOSubWriter)
|
||||
@ -43,13 +44,17 @@ type
|
||||
{ _TMachOSymbolTable_ }
|
||||
|
||||
function _TMachOSymbolTable_.AddSymbol(aName: string; sect: byte; addr: longword;
|
||||
glob: boolean): integer;
|
||||
glob, undef: boolean): integer;
|
||||
var p : _PNlist_;
|
||||
begin
|
||||
p:=GetMem(sizeof(_TNlist_));
|
||||
p^.strx:=fStringTable.Add(aName);
|
||||
p^._type:=N_SECT;
|
||||
if glob then p^._type:=p^._type or N_EXT;
|
||||
if not undef then
|
||||
p^._type:=N_SECT
|
||||
else
|
||||
p^._type:=N_UNDF;
|
||||
if glob then
|
||||
p^._type:=p^._type or N_EXT;
|
||||
p^.desc:=0;
|
||||
p^.sect:=sect;
|
||||
p^.value:=addr;
|
||||
@ -60,10 +65,20 @@ end;
|
||||
procedure _TMachOSymbolTable_.WriteToStream(aStream: TStream);
|
||||
var nlist : _TNlist_;
|
||||
i : integer;
|
||||
sawglobal: boolean;
|
||||
begin
|
||||
{ first write local symbols, then global ones, as ilocalsym is hardcoded to
|
||||
be index 0. Can't reorder here because we may already have used symbol
|
||||
numbers to generate relocations -> give an error if a global symbol
|
||||
comes before any local symbols }
|
||||
sawglobal:=false;
|
||||
for i:=0 to fList.Count-1 do
|
||||
begin
|
||||
nlist:=_PNlist_(fList[i])^;
|
||||
if (nlist._type and N_EXT)<>0 then
|
||||
sawglobal:=true
|
||||
else if sawglobal then
|
||||
raise EMachOResourceWriterSymbolTableWrongOrderException.Create('');
|
||||
if fOppositeEndianess then
|
||||
begin
|
||||
nlist.strx:=SwapEndian(nlist.strx);
|
||||
@ -74,6 +89,14 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure _TMachOSymbolTable_.SetSymbolOffset(symbolnum: integer; offset: longword);
|
||||
var
|
||||
p : _PNlist_;
|
||||
begin
|
||||
p:=_PNlist_(flist[symbolnum]);
|
||||
p^.value:=offset;
|
||||
end;
|
||||
|
||||
{ _TMachOSubWriter_ }
|
||||
|
||||
procedure _TMachOSubWriter_.SwapSection(var aSection: _TSection_);
|
||||
@ -108,8 +131,13 @@ begin
|
||||
hdr.count:=aResources.Count;
|
||||
hdr.usedhandles:=0;
|
||||
hdr.handles:=0;
|
||||
fRelocations.Add(0,1);
|
||||
fRelocations.Add(sizeof(hdr.rootptr)+sizeof(hdr.count)+sizeof(hdr.usedhandles),2);
|
||||
{ the first pointer (rootptr at offset 0) goes to the root node, which comes
|
||||
right after the header (the addend has been set to sizeof(hdr) -> add the
|
||||
address of the fpc.resources section to it via a relocations}
|
||||
fRelocations.Add(0,ffpcresourcessym);
|
||||
{ the last pointer (handles at offset sizeof(fields before it)) goes to the
|
||||
fpc.reshandles section }
|
||||
fRelocations.Add(sizeof(hdr.rootptr)+sizeof(hdr.count)+sizeof(hdr.usedhandles),ffpcreshandlessym);
|
||||
if fOppositeEndianess then
|
||||
begin
|
||||
hdr.rootptr:=SwapEndian(hdr.rootptr);
|
||||
@ -123,6 +151,7 @@ end;
|
||||
|
||||
procedure _TMachOSubWriter_.WriteNodeInfos(aStream: TStream);
|
||||
begin
|
||||
{ offset inside the object }
|
||||
fCurOfs:=sizeof(_TResHdr_);
|
||||
WriteNodeInfo(aStream,fRoot);
|
||||
WriteSubNodes(aStream,fRoot);
|
||||
@ -137,7 +166,7 @@ begin
|
||||
else
|
||||
begin
|
||||
infonode.nameid:=fResStrTable.StartOfs+aNode.NameRVA;
|
||||
fRelocations.Add(fCurOfs,1);
|
||||
fRelocations.Add(fCurOfs,ffpcresourcessym);
|
||||
end;
|
||||
infonode.ncount:=aNode.NamedCount;
|
||||
if aNode.IsLeaf then
|
||||
@ -153,7 +182,7 @@ begin
|
||||
end;
|
||||
fRelocations.Add(
|
||||
fCurOfs+sizeof(infonode.nameid)+sizeof(infonode.ncount)+
|
||||
sizeof(infonode.idcountsize),1);
|
||||
sizeof(infonode.idcountsize),ffpcresourcessym);
|
||||
if fOppositeEndianess then
|
||||
begin
|
||||
infonode.nameid:=SwapEndian(infonode.nameid);
|
||||
@ -170,7 +199,7 @@ var buf : pbyte;
|
||||
begin
|
||||
fHeader.sizeofcmds:=
|
||||
//segment+res section+bss section
|
||||
sizeof(_TSegmentCommand_)+sizeof(_TSection_)*2+
|
||||
sizeof(_TSegmentCommand_)+sizeof(_TSection_)*3+
|
||||
//symbol table and dynamic symbol table commands
|
||||
sizeof(TSymtabCommand)+sizeof(TDySymtabCommand)+
|
||||
//common header of the three commands
|
||||
@ -189,21 +218,35 @@ var ldcommand : TLoadCommand;
|
||||
segcommand : _TSegmentCommand_;
|
||||
symcommand : TSymtabCommand;
|
||||
dysymcommand : TDySymtabCommand;
|
||||
ressection,bsssection : _TSection_;
|
||||
ressection,bsssection,textsection : _TSection_;
|
||||
begin
|
||||
ldcommand.cmd:=fSegType;
|
||||
ldcommand.cmdsize:=sizeof(TLoadCommand)+sizeof(segcommand)+sizeof(ressection)*2;
|
||||
ldcommand.cmdsize:=sizeof(TLoadCommand)+sizeof(segcommand)+sizeof(ressection)*3;
|
||||
|
||||
FillByte(segcommand.name[0],16,0);
|
||||
segcommand.vmaddr:=0;
|
||||
segcommand.vmsize:=fDataCurOfs+sizeof(_ptrtype_)*aResources.Count;
|
||||
segcommand.fileoff:=fSectionStart;
|
||||
segcommand.filesize:=fDataCurOfs;
|
||||
segcommand.maxprot:=VM_PROT_READ or VM_PROT_WRITE;
|
||||
segcommand.initprot:=VM_PROT_READ or VM_PROT_WRITE;
|
||||
segcommand.nsects:=2;
|
||||
segcommand.maxprot:=VM_PROT_READ or VM_PROT_WRITE or VM_PROT_EXECUTE;
|
||||
segcommand.initprot:=VM_PROT_READ or VM_PROT_WRITE or VM_PROT_EXECUTE;
|
||||
segcommand.nsects:=3;
|
||||
segcommand.flags:=0;
|
||||
|
||||
fillbyte(textsection,sizeof(textsection),0);
|
||||
textsection.sectname:='__text';
|
||||
textsection.segname:='__TEXT';
|
||||
textsection.addr:=0;
|
||||
textsection.size:=0;
|
||||
textsection.offset:=segcommand.fileoff;
|
||||
textsection.align:=0;
|
||||
textsection.reloff:=0;
|
||||
textsection.nreloc:=0;
|
||||
textsection.flags:=S_ATTR_PURE_INSTRUCTIONS;
|
||||
textsection.reserved1:=0;
|
||||
textsection.reserved2:=0;
|
||||
|
||||
fillbyte(ressection,sizeof(ressection),0);
|
||||
ressection.sectname:=RsrcSectName;
|
||||
ressection.segname:=DataSegName;
|
||||
ressection.addr:=0;
|
||||
@ -216,6 +259,7 @@ begin
|
||||
ressection.reserved1:=0;
|
||||
ressection.reserved2:=0;
|
||||
|
||||
fillbyte(bsssection,sizeof(bsssection),0);
|
||||
bsssection.sectname:=HandlesSectName;
|
||||
bsssection.segname:=DataSegName;
|
||||
bsssection.addr:=fDataCurOfs;
|
||||
@ -242,12 +286,14 @@ begin
|
||||
segcommand.nsects:=SwapEndian(segcommand.nsects);
|
||||
segcommand.flags:=SwapEndian(segcommand.flags);
|
||||
|
||||
SwapSection(textsection);
|
||||
SwapSection(ressection);
|
||||
SwapSection(bsssection);
|
||||
end;
|
||||
|
||||
aStream.WriteBuffer(ldcommand,sizeof(ldcommand));
|
||||
aStream.WriteBuffer(segcommand,sizeof(segcommand));
|
||||
aStream.WriteBuffer(textsection,sizeof(textsection));
|
||||
aStream.WriteBuffer(ressection,sizeof(ressection));
|
||||
aStream.WriteBuffer(bsssection,sizeof(bsssection));
|
||||
|
||||
|
@ -25,6 +25,7 @@ uses
|
||||
type
|
||||
EMachOResourceWriterException = class(EResourceWriterException);
|
||||
EMachOResourceWriterUnknownBitSizeException = class(EMachOResourceWriterException);
|
||||
EMachOResourceWriterSymbolTableWrongOrderException = class(EMachOResourceWriterException);
|
||||
|
||||
type
|
||||
|
||||
@ -86,7 +87,7 @@ type
|
||||
public
|
||||
constructor Create(aMachineType : TMachOMachineType; aOppositeEndianess : boolean);
|
||||
destructor Destroy; override;
|
||||
procedure Add(addr : longword; sectnum : longword);
|
||||
procedure Add(addr: longword; symnum: longword);
|
||||
procedure Clear;
|
||||
procedure WriteToStream(aStream : TStream);
|
||||
property Count : integer read GetCount;
|
||||
@ -105,15 +106,17 @@ type
|
||||
fOppositeEndianess : boolean;
|
||||
function GetCount : integer;
|
||||
function AddSymbol(aName : string; sect : byte; addr : longword;
|
||||
glob : boolean) : integer; virtual; abstract;
|
||||
glob, undef : boolean) : integer; virtual; abstract;
|
||||
protected
|
||||
public
|
||||
constructor Create(aStringTable : TObjectStringTable);
|
||||
destructor Destroy; override;
|
||||
function AddLocal(aName : string; sect : byte; addr : longword) : integer;
|
||||
function AddGlobal(aName : string; sect : byte; addr : longword) : integer;
|
||||
function AddLocal(const aName : string; sect : byte; addr : longword) : integer;
|
||||
function AddGlobal(const aName : string; sect : byte; addr : longword) : integer;
|
||||
function AddExternal(const aName : string) : integer;
|
||||
procedure Clear;
|
||||
procedure WriteToStream(aStream : TStream); virtual; abstract;
|
||||
procedure SetSymbolOffset(symbolnum : integer; offset: longword); virtual; abstract;
|
||||
property Count : integer read GetCount;
|
||||
property LocalCount : integer read fLocalCount;
|
||||
property GlobalCount : integer read fGlobalCount;
|
||||
@ -141,6 +144,8 @@ type
|
||||
fCurOfs : longword;
|
||||
fDataCurOfs : longword;
|
||||
fSectionStart : longword;
|
||||
ffpcresourcessym,
|
||||
ffpcreshandlessym : integer;
|
||||
|
||||
function NextAligned(aBound, aValue : longword) : longword;
|
||||
procedure Align(aBound : integer; aStream : TStream);
|
||||
@ -241,17 +246,23 @@ begin
|
||||
fList.Free;
|
||||
end;
|
||||
|
||||
function TMachOSymbolTable.AddLocal(aName: string; sect: byte; addr: longword
|
||||
function TMachOSymbolTable.AddLocal(const aName: string; sect: byte; addr: longword
|
||||
): integer;
|
||||
begin
|
||||
Result:=AddSymbol(aName,sect,addr,false);
|
||||
Result:=AddSymbol(aName,sect,addr,false,false);
|
||||
inc(fLocalCount);
|
||||
end;
|
||||
|
||||
function TMachOSymbolTable.AddGlobal(aName: string; sect: byte; addr: longword
|
||||
function TMachOSymbolTable.AddGlobal(const aName: string; sect: byte; addr: longword
|
||||
): integer;
|
||||
begin
|
||||
Result:=AddSymbol(aName,sect,addr,true);
|
||||
Result:=AddSymbol(aName,sect,addr,true,false);
|
||||
inc(fGlobalCount);
|
||||
end;
|
||||
|
||||
function TMachOSymbolTable.AddExternal(const aName: string): integer;
|
||||
begin
|
||||
Result:=AddSymbol(aName,NO_SECT,0,false,true);
|
||||
inc(fGlobalCount);
|
||||
end;
|
||||
|
||||
@ -317,7 +328,7 @@ begin
|
||||
fList.Free;
|
||||
end;
|
||||
|
||||
procedure TMachORelocations.Add(addr: longword; sectnum: longword);
|
||||
procedure TMachORelocations.Add(addr: longword; symnum: longword);
|
||||
var p : PRelocationInfo;
|
||||
begin
|
||||
p:=GetMem(sizeof(TRelocationInfo));
|
||||
@ -325,15 +336,19 @@ begin
|
||||
//bit fields make things difficult...
|
||||
if fEndianess=MACH_BIG_ENDIAN then
|
||||
begin
|
||||
p^.flags:=sectnum shl 8;
|
||||
p^.flags:=symnum shl 8;
|
||||
p^.flags:=p^.flags or (fRelocSize shl 5); //length
|
||||
p^.flags:=p^.flags or fRelocType;
|
||||
{ reference via symbol }
|
||||
p^.flags:=p^.flags or R_EXTERN_BE;
|
||||
end
|
||||
else
|
||||
begin
|
||||
p^.flags:=sectnum and R_SYMBOLNUM_LE;
|
||||
p^.flags:=symnum and R_SYMBOLNUM_LE;
|
||||
p^.flags:=p^.flags or (fRelocSize shl 25); //length
|
||||
p^.flags:=p^.flags or (fRelocType shl 28);
|
||||
{ reference via symbol }
|
||||
p^.flags:=p^.flags or R_EXTERN_LE;
|
||||
end;
|
||||
fList.Add(p);
|
||||
end;
|
||||
@ -556,15 +571,33 @@ begin
|
||||
AllocateSpaceForLoadCommands(aStream);
|
||||
fSectionStart:=aStream.Position;
|
||||
fRoot:=TRootResTreeNode(fParent.GetTree(aResources));
|
||||
{ on AArch64, if you want to refer to a section from another one, you
|
||||
have to do it via an explicit symbol reference.
|
||||
|
||||
}
|
||||
{ dummy text section symbol }
|
||||
fSymbolTable.AddLocal('ltmp0',1,0);
|
||||
{ dummy fpc.resources symbol }
|
||||
fSymbolTable.AddLocal('ltmp1',2,0);
|
||||
{ the offset needs to be the offset in the file, *not* relative to the start
|
||||
of the section. We don't know here yet how large the fpcresources section
|
||||
will be -> fix up later }
|
||||
ffpcreshandlessym:=fSymbolTable.AddGlobal('__fpc_reshandles_internal',3,0);
|
||||
{ don't add this before any local symbols, as local symbols must be written
|
||||
first. We can't reorder while writing the symbol table, because we already
|
||||
need the symbol numbers above }
|
||||
ffpcresourcessym:=fSymbolTable.AddGlobal('FPC_RESSYMBOL',2,0);
|
||||
|
||||
PrescanResourceTree;
|
||||
WriteResHeader(aStream,aResources);
|
||||
WriteNodeInfos(aStream);
|
||||
WriteResStringTable(aStream);
|
||||
WriteRawData(aStream);
|
||||
// fSymbolTable.AddGlobal('FPCRES_SECTION',1,0);
|
||||
fSymbolTable.AddGlobal('FPC_RESSYMBOL',1,0);
|
||||
fRelocations.StartOfs:=aStream.Position;
|
||||
WriteRelocations(aStream);
|
||||
|
||||
{ fix up offset of fpcreshandles symbol }
|
||||
fSymbolTable.SetSymbolOffset(ffpcreshandlessym,fDataCurOfs);
|
||||
fSymbolTable.StartOfs:=aStream.Position;
|
||||
WriteSymbolTable(aStream);
|
||||
fMachOStringTable.StartOfs:=aStream.Position;
|
||||
|
Loading…
Reference in New Issue
Block a user