* 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:
Jonas Maebe 2015-02-24 20:57:39 +00:00
parent 5302024e25
commit 6149d37e2a
3 changed files with 108 additions and 27 deletions

View File

@ -183,6 +183,8 @@ const
N_SECT = $e; // defined in section number n_sect N_SECT = $e; // defined in section number n_sect
N_PBUD = $c; // prebound undefined (defined in a dylib) N_PBUD = $c; // prebound undefined (defined in a dylib)
N_INDR = $a; // indirect N_INDR = $a; // indirect
NO_SECT = $0; // symbol is not in any section
//Relocations: masks for flag //Relocations: masks for flag
R_SYMBOLNUM_BE = $FFFFFF00; R_SYMBOLNUM_BE = $FFFFFF00;

View File

@ -17,10 +17,11 @@ type
_TMachOSymbolTable_ = class(TMachOSymbolTable) _TMachOSymbolTable_ = class(TMachOSymbolTable)
protected protected
function AddSymbol(aName : string; sect : byte; addr : longword; function AddSymbol(aName : string; sect : byte; addr : longword;
glob : boolean) : integer; override; glob, undef : boolean) : integer; override;
protected protected
public public
procedure WriteToStream(aStream : TStream); override; procedure WriteToStream(aStream : TStream); override;
procedure SetSymbolOffset(symbolnum : integer; offset: longword); override;
end; end;
_TMachOSubWriter_ = class(TAbstractMachOSubWriter) _TMachOSubWriter_ = class(TAbstractMachOSubWriter)
@ -43,13 +44,17 @@ type
{ _TMachOSymbolTable_ } { _TMachOSymbolTable_ }
function _TMachOSymbolTable_.AddSymbol(aName: string; sect: byte; addr: longword; function _TMachOSymbolTable_.AddSymbol(aName: string; sect: byte; addr: longword;
glob: boolean): integer; glob, undef: boolean): integer;
var p : _PNlist_; var p : _PNlist_;
begin begin
p:=GetMem(sizeof(_TNlist_)); p:=GetMem(sizeof(_TNlist_));
p^.strx:=fStringTable.Add(aName); p^.strx:=fStringTable.Add(aName);
p^._type:=N_SECT; if not undef then
if glob then p^._type:=p^._type or N_EXT; p^._type:=N_SECT
else
p^._type:=N_UNDF;
if glob then
p^._type:=p^._type or N_EXT;
p^.desc:=0; p^.desc:=0;
p^.sect:=sect; p^.sect:=sect;
p^.value:=addr; p^.value:=addr;
@ -60,10 +65,20 @@ end;
procedure _TMachOSymbolTable_.WriteToStream(aStream: TStream); procedure _TMachOSymbolTable_.WriteToStream(aStream: TStream);
var nlist : _TNlist_; var nlist : _TNlist_;
i : integer; i : integer;
sawglobal: boolean;
begin 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 for i:=0 to fList.Count-1 do
begin begin
nlist:=_PNlist_(fList[i])^; nlist:=_PNlist_(fList[i])^;
if (nlist._type and N_EXT)<>0 then
sawglobal:=true
else if sawglobal then
raise EMachOResourceWriterSymbolTableWrongOrderException.Create('');
if fOppositeEndianess then if fOppositeEndianess then
begin begin
nlist.strx:=SwapEndian(nlist.strx); nlist.strx:=SwapEndian(nlist.strx);
@ -74,6 +89,14 @@ begin
end; end;
end; end;
procedure _TMachOSymbolTable_.SetSymbolOffset(symbolnum: integer; offset: longword);
var
p : _PNlist_;
begin
p:=_PNlist_(flist[symbolnum]);
p^.value:=offset;
end;
{ _TMachOSubWriter_ } { _TMachOSubWriter_ }
procedure _TMachOSubWriter_.SwapSection(var aSection: _TSection_); procedure _TMachOSubWriter_.SwapSection(var aSection: _TSection_);
@ -108,8 +131,13 @@ begin
hdr.count:=aResources.Count; hdr.count:=aResources.Count;
hdr.usedhandles:=0; hdr.usedhandles:=0;
hdr.handles:=0; hdr.handles:=0;
fRelocations.Add(0,1); { the first pointer (rootptr at offset 0) goes to the root node, which comes
fRelocations.Add(sizeof(hdr.rootptr)+sizeof(hdr.count)+sizeof(hdr.usedhandles),2); 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 if fOppositeEndianess then
begin begin
hdr.rootptr:=SwapEndian(hdr.rootptr); hdr.rootptr:=SwapEndian(hdr.rootptr);
@ -123,6 +151,7 @@ end;
procedure _TMachOSubWriter_.WriteNodeInfos(aStream: TStream); procedure _TMachOSubWriter_.WriteNodeInfos(aStream: TStream);
begin begin
{ offset inside the object }
fCurOfs:=sizeof(_TResHdr_); fCurOfs:=sizeof(_TResHdr_);
WriteNodeInfo(aStream,fRoot); WriteNodeInfo(aStream,fRoot);
WriteSubNodes(aStream,fRoot); WriteSubNodes(aStream,fRoot);
@ -137,7 +166,7 @@ begin
else else
begin begin
infonode.nameid:=fResStrTable.StartOfs+aNode.NameRVA; infonode.nameid:=fResStrTable.StartOfs+aNode.NameRVA;
fRelocations.Add(fCurOfs,1); fRelocations.Add(fCurOfs,ffpcresourcessym);
end; end;
infonode.ncount:=aNode.NamedCount; infonode.ncount:=aNode.NamedCount;
if aNode.IsLeaf then if aNode.IsLeaf then
@ -153,7 +182,7 @@ begin
end; end;
fRelocations.Add( fRelocations.Add(
fCurOfs+sizeof(infonode.nameid)+sizeof(infonode.ncount)+ fCurOfs+sizeof(infonode.nameid)+sizeof(infonode.ncount)+
sizeof(infonode.idcountsize),1); sizeof(infonode.idcountsize),ffpcresourcessym);
if fOppositeEndianess then if fOppositeEndianess then
begin begin
infonode.nameid:=SwapEndian(infonode.nameid); infonode.nameid:=SwapEndian(infonode.nameid);
@ -170,7 +199,7 @@ var buf : pbyte;
begin begin
fHeader.sizeofcmds:= fHeader.sizeofcmds:=
//segment+res section+bss section //segment+res section+bss section
sizeof(_TSegmentCommand_)+sizeof(_TSection_)*2+ sizeof(_TSegmentCommand_)+sizeof(_TSection_)*3+
//symbol table and dynamic symbol table commands //symbol table and dynamic symbol table commands
sizeof(TSymtabCommand)+sizeof(TDySymtabCommand)+ sizeof(TSymtabCommand)+sizeof(TDySymtabCommand)+
//common header of the three commands //common header of the three commands
@ -189,21 +218,35 @@ var ldcommand : TLoadCommand;
segcommand : _TSegmentCommand_; segcommand : _TSegmentCommand_;
symcommand : TSymtabCommand; symcommand : TSymtabCommand;
dysymcommand : TDySymtabCommand; dysymcommand : TDySymtabCommand;
ressection,bsssection : _TSection_; ressection,bsssection,textsection : _TSection_;
begin begin
ldcommand.cmd:=fSegType; 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); FillByte(segcommand.name[0],16,0);
segcommand.vmaddr:=0; segcommand.vmaddr:=0;
segcommand.vmsize:=fDataCurOfs+sizeof(_ptrtype_)*aResources.Count; segcommand.vmsize:=fDataCurOfs+sizeof(_ptrtype_)*aResources.Count;
segcommand.fileoff:=fSectionStart; segcommand.fileoff:=fSectionStart;
segcommand.filesize:=fDataCurOfs; segcommand.filesize:=fDataCurOfs;
segcommand.maxprot:=VM_PROT_READ or VM_PROT_WRITE; segcommand.maxprot:=VM_PROT_READ or VM_PROT_WRITE or VM_PROT_EXECUTE;
segcommand.initprot:=VM_PROT_READ or VM_PROT_WRITE; segcommand.initprot:=VM_PROT_READ or VM_PROT_WRITE or VM_PROT_EXECUTE;
segcommand.nsects:=2; segcommand.nsects:=3;
segcommand.flags:=0; 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.sectname:=RsrcSectName;
ressection.segname:=DataSegName; ressection.segname:=DataSegName;
ressection.addr:=0; ressection.addr:=0;
@ -216,6 +259,7 @@ begin
ressection.reserved1:=0; ressection.reserved1:=0;
ressection.reserved2:=0; ressection.reserved2:=0;
fillbyte(bsssection,sizeof(bsssection),0);
bsssection.sectname:=HandlesSectName; bsssection.sectname:=HandlesSectName;
bsssection.segname:=DataSegName; bsssection.segname:=DataSegName;
bsssection.addr:=fDataCurOfs; bsssection.addr:=fDataCurOfs;
@ -242,12 +286,14 @@ begin
segcommand.nsects:=SwapEndian(segcommand.nsects); segcommand.nsects:=SwapEndian(segcommand.nsects);
segcommand.flags:=SwapEndian(segcommand.flags); segcommand.flags:=SwapEndian(segcommand.flags);
SwapSection(textsection);
SwapSection(ressection); SwapSection(ressection);
SwapSection(bsssection); SwapSection(bsssection);
end; end;
aStream.WriteBuffer(ldcommand,sizeof(ldcommand)); aStream.WriteBuffer(ldcommand,sizeof(ldcommand));
aStream.WriteBuffer(segcommand,sizeof(segcommand)); aStream.WriteBuffer(segcommand,sizeof(segcommand));
aStream.WriteBuffer(textsection,sizeof(textsection));
aStream.WriteBuffer(ressection,sizeof(ressection)); aStream.WriteBuffer(ressection,sizeof(ressection));
aStream.WriteBuffer(bsssection,sizeof(bsssection)); aStream.WriteBuffer(bsssection,sizeof(bsssection));

View File

@ -25,6 +25,7 @@ uses
type type
EMachOResourceWriterException = class(EResourceWriterException); EMachOResourceWriterException = class(EResourceWriterException);
EMachOResourceWriterUnknownBitSizeException = class(EMachOResourceWriterException); EMachOResourceWriterUnknownBitSizeException = class(EMachOResourceWriterException);
EMachOResourceWriterSymbolTableWrongOrderException = class(EMachOResourceWriterException);
type type
@ -86,7 +87,7 @@ type
public public
constructor Create(aMachineType : TMachOMachineType; aOppositeEndianess : boolean); constructor Create(aMachineType : TMachOMachineType; aOppositeEndianess : boolean);
destructor Destroy; override; destructor Destroy; override;
procedure Add(addr : longword; sectnum : longword); procedure Add(addr: longword; symnum: longword);
procedure Clear; procedure Clear;
procedure WriteToStream(aStream : TStream); procedure WriteToStream(aStream : TStream);
property Count : integer read GetCount; property Count : integer read GetCount;
@ -105,15 +106,17 @@ type
fOppositeEndianess : boolean; fOppositeEndianess : boolean;
function GetCount : integer; function GetCount : integer;
function AddSymbol(aName : string; sect : byte; addr : longword; function AddSymbol(aName : string; sect : byte; addr : longword;
glob : boolean) : integer; virtual; abstract; glob, undef : boolean) : integer; virtual; abstract;
protected protected
public public
constructor Create(aStringTable : TObjectStringTable); constructor Create(aStringTable : TObjectStringTable);
destructor Destroy; override; destructor Destroy; override;
function AddLocal(aName : string; sect : byte; addr : longword) : integer; function AddLocal(const aName : string; sect : byte; addr : longword) : integer;
function AddGlobal(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 Clear;
procedure WriteToStream(aStream : TStream); virtual; abstract; procedure WriteToStream(aStream : TStream); virtual; abstract;
procedure SetSymbolOffset(symbolnum : integer; offset: longword); virtual; abstract;
property Count : integer read GetCount; property Count : integer read GetCount;
property LocalCount : integer read fLocalCount; property LocalCount : integer read fLocalCount;
property GlobalCount : integer read fGlobalCount; property GlobalCount : integer read fGlobalCount;
@ -141,6 +144,8 @@ type
fCurOfs : longword; fCurOfs : longword;
fDataCurOfs : longword; fDataCurOfs : longword;
fSectionStart : longword; fSectionStart : longword;
ffpcresourcessym,
ffpcreshandlessym : integer;
function NextAligned(aBound, aValue : longword) : longword; function NextAligned(aBound, aValue : longword) : longword;
procedure Align(aBound : integer; aStream : TStream); procedure Align(aBound : integer; aStream : TStream);
@ -241,17 +246,23 @@ begin
fList.Free; fList.Free;
end; end;
function TMachOSymbolTable.AddLocal(aName: string; sect: byte; addr: longword function TMachOSymbolTable.AddLocal(const aName: string; sect: byte; addr: longword
): integer; ): integer;
begin begin
Result:=AddSymbol(aName,sect,addr,false); Result:=AddSymbol(aName,sect,addr,false,false);
inc(fLocalCount); inc(fLocalCount);
end; end;
function TMachOSymbolTable.AddGlobal(aName: string; sect: byte; addr: longword function TMachOSymbolTable.AddGlobal(const aName: string; sect: byte; addr: longword
): integer; ): integer;
begin 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); inc(fGlobalCount);
end; end;
@ -317,7 +328,7 @@ begin
fList.Free; fList.Free;
end; end;
procedure TMachORelocations.Add(addr: longword; sectnum: longword); procedure TMachORelocations.Add(addr: longword; symnum: longword);
var p : PRelocationInfo; var p : PRelocationInfo;
begin begin
p:=GetMem(sizeof(TRelocationInfo)); p:=GetMem(sizeof(TRelocationInfo));
@ -325,15 +336,19 @@ begin
//bit fields make things difficult... //bit fields make things difficult...
if fEndianess=MACH_BIG_ENDIAN then if fEndianess=MACH_BIG_ENDIAN then
begin 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 (fRelocSize shl 5); //length
p^.flags:=p^.flags or fRelocType; p^.flags:=p^.flags or fRelocType;
{ reference via symbol }
p^.flags:=p^.flags or R_EXTERN_BE;
end end
else else
begin 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 (fRelocSize shl 25); //length
p^.flags:=p^.flags or (fRelocType shl 28); p^.flags:=p^.flags or (fRelocType shl 28);
{ reference via symbol }
p^.flags:=p^.flags or R_EXTERN_LE;
end; end;
fList.Add(p); fList.Add(p);
end; end;
@ -556,15 +571,33 @@ begin
AllocateSpaceForLoadCommands(aStream); AllocateSpaceForLoadCommands(aStream);
fSectionStart:=aStream.Position; fSectionStart:=aStream.Position;
fRoot:=TRootResTreeNode(fParent.GetTree(aResources)); 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; PrescanResourceTree;
WriteResHeader(aStream,aResources); WriteResHeader(aStream,aResources);
WriteNodeInfos(aStream); WriteNodeInfos(aStream);
WriteResStringTable(aStream); WriteResStringTable(aStream);
WriteRawData(aStream); WriteRawData(aStream);
// fSymbolTable.AddGlobal('FPCRES_SECTION',1,0);
fSymbolTable.AddGlobal('FPC_RESSYMBOL',1,0);
fRelocations.StartOfs:=aStream.Position; fRelocations.StartOfs:=aStream.Position;
WriteRelocations(aStream); WriteRelocations(aStream);
{ fix up offset of fpcreshandles symbol }
fSymbolTable.SetSymbolOffset(ffpcreshandlessym,fDataCurOfs);
fSymbolTable.StartOfs:=aStream.Position; fSymbolTable.StartOfs:=aStream.Position;
WriteSymbolTable(aStream); WriteSymbolTable(aStream);
fMachOStringTable.StartOfs:=aStream.Position; fMachOStringTable.StartOfs:=aStream.Position;