Browse Source

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

Jonas Maebe 10 years ago
parent
commit
6149d37e2a

+ 2 - 0
packages/fcl-res/src/machoconsts.pp

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

+ 60 - 14
packages/fcl-res/src/machosubwriter.inc

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

+ 46 - 13
packages/fcl-res/src/machowriter.pp

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