* 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_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;

View File

@ -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));

View File

@ -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;