1{ 2 This file is part of the Free Pascal run time library. 3 Copyright (c) 2008 by Giulio Bernardi 4 5 Resource writer for Mach-O files 6 7 See the file COPYING.FPC, included in this distribution, 8 for details about the copyright. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 14 **********************************************************************} 15 16type 17 _TMachOSymbolTable_ = class(TMachOSymbolTable) 18 protected 19 function AddSymbol(aName : string; sect : byte; addr : longword; 20 glob, undef : boolean) : integer; override; 21 protected 22 public 23 procedure WriteToStream(aStream : TStream); override; 24 procedure SetSymbolOffset(symbolnum : integer; offset: longword); override; 25 end; 26 27 _TMachOSubWriter_ = class(TAbstractMachOSubWriter) 28 private 29 procedure SwapSection(var aSection: _TSection_); 30 protected 31 procedure PrescanResourceTree; override; 32 procedure WriteResHeader(aStream : TStream; aResources : TResources); override; 33 procedure WriteNodeInfos(aStream : TStream); override; 34 procedure WriteNodeInfo(aStream : TStream; aNode : TResourceTreeNode); override; 35 procedure AllocateSpaceForLoadCommands(aStream : TStream); override; 36 37 procedure FixLoadCommands(aStream : TStream; aResources : TResources); override; 38 public 39 constructor Create(aParent : TMachOResourceWriter; const aMachineType 40 : TMachOMachineType; const aSubMachineType: TMachoSubMachineType; 41 const aOppositeEndianess : boolean); override; 42 end; 43 44{ _TMachOSymbolTable_ } 45 46function _TMachOSymbolTable_.AddSymbol(aName: string; sect: byte; addr: longword; 47 glob, undef: boolean): integer; 48var p : _PNlist_; 49begin 50 p:=GetMem(sizeof(_TNlist_)); 51 p^.strx:=fStringTable.Add(aName); 52 if not undef then 53 p^._type:=N_SECT 54 else 55 p^._type:=N_UNDF; 56 if glob then 57 p^._type:=p^._type or N_EXT; 58 p^.desc:=0; 59 p^.sect:=sect; 60 p^.value:=addr; 61 Result:=fList.Count; 62 fList.Add(p); 63end; 64 65procedure _TMachOSymbolTable_.WriteToStream(aStream: TStream); 66var nlist : _TNlist_; 67 i : integer; 68 sawglobal: boolean; 69begin 70 { first write local symbols, then global ones, as ilocalsym is hardcoded to 71 be index 0. Can't reorder here because we may already have used symbol 72 numbers to generate relocations -> give an error if a global symbol 73 comes before any local symbols } 74 sawglobal:=false; 75 for i:=0 to fList.Count-1 do 76 begin 77 nlist:=_PNlist_(fList[i])^; 78 if (nlist._type and N_EXT)<>0 then 79 sawglobal:=true 80 else if sawglobal then 81 raise EMachOResourceWriterSymbolTableWrongOrderException.Create(''); 82 if fOppositeEndianess then 83 begin 84 nlist.strx:=SwapEndian(nlist.strx); 85 nlist.desc:=SwapEndian(nlist.desc); 86 nlist.value:=SwapEndian(nlist.value); 87 end; 88 aStream.WriteBuffer(nlist,sizeof(nlist)); 89 end; 90end; 91 92procedure _TMachOSymbolTable_.SetSymbolOffset(symbolnum: integer; offset: longword); 93var 94 p : _PNlist_; 95begin 96 p:=_PNlist_(flist[symbolnum]); 97 p^.value:=offset; 98end; 99 100{ _TMachOSubWriter_ } 101 102procedure _TMachOSubWriter_.SwapSection(var aSection: _TSection_); 103begin 104 aSection.addr:=SwapEndian(aSection.addr); 105 aSection.size:=SwapEndian(aSection.size); 106 aSection.offset:=SwapEndian(aSection.offset); 107 aSection.align:=SwapEndian(aSection.align); 108 aSection.reloff:=SwapEndian(aSection.reloff); 109 aSection.nreloc:=SwapEndian(aSection.nreloc); 110 aSection.flags:=SwapEndian(aSection.flags); 111 aSection.reserved1:=SwapEndian(aSection.reserved1); 112 aSection.reserved2:=SwapEndian(aSection.reserved2); 113end; 114 115procedure _TMachOSubWriter_.PrescanResourceTree; 116begin 117 fResStrTable.Clear; 118 fRoot.SubDirRVA:=sizeof(_TResHdr_)+sizeof(_TResInfoNode_); 119 fResStrTable.StartOfs:=PrescanNode(fRoot,sizeof(_TResInfoNode_)); 120 if fResStrTable.Used then 121 fDataCurOfs:=NextAligned(fDataAlignment,fResStrTable.StartOfs+fResStrTable.Size) 122 else 123 fDataCurOfs:=fResStrTable.StartOfs; 124end; 125 126procedure _TMachOSubWriter_.WriteResHeader(aStream: TStream; 127 aResources: TResources); 128var hdr : _TResHdr_; 129begin 130 hdr.rootptr:=sizeof(hdr); 131 hdr.count:=aResources.Count; 132 hdr.usedhandles:=0; 133 hdr.handles:=0; 134 { the first pointer (rootptr at offset 0) goes to the root node, which comes 135 right after the header (the addend has been set to sizeof(hdr) -> add the 136 address of the fpc.resources section to it via a relocations} 137 fRelocations.Add(0,ffpcresourcessym); 138 { the last pointer (handles at offset sizeof(fields before it)) goes to the 139 fpc.reshandles section } 140 fRelocations.Add(sizeof(hdr.rootptr)+sizeof(hdr.count)+sizeof(hdr.usedhandles),ffpcreshandlessym); 141 if fOppositeEndianess then 142 begin 143 hdr.rootptr:=SwapEndian(hdr.rootptr); 144 hdr.count:=SwapEndian(hdr.count); 145 //handles must be fixed later 146// hdr.usedhandles:=SwapEndian(hdr.usedhandles); 147// hdr.handles:=SwapEndian(hdr.handles); 148 end; 149 aStream.WriteBuffer(hdr,sizeof(hdr)); 150end; 151 152procedure _TMachOSubWriter_.WriteNodeInfos(aStream: TStream); 153begin 154 { offset inside the object } 155 fCurOfs:=sizeof(_TResHdr_); 156 WriteNodeInfo(aStream,fRoot); 157 WriteSubNodes(aStream,fRoot); 158end; 159 160procedure _TMachOSubWriter_.WriteNodeInfo(aStream: TStream; 161 aNode: TResourceTreeNode); 162var infonode : _TResInfoNode_; 163begin 164 if aNode.Desc.DescType=dtID then 165 infonode.nameid:=aNode.Desc.ID 166 else 167 begin 168 infonode.nameid:=fResStrTable.StartOfs+aNode.NameRVA; 169 fRelocations.Add(fCurOfs,ffpcresourcessym); 170 end; 171 infonode.ncount:=aNode.NamedCount; 172 if aNode.IsLeaf then 173 begin 174 infonode.idcountsize:=aNode.Data.RawData.Size; 175 infonode.subptr:=fDataCurOfs; 176 fDataCurOfs:=NextAligned(fDataAlignment,fDataCurOfs+infonode.idcountsize); 177 end 178 else 179 begin 180 infonode.idcountsize:=aNode.IDCount; 181 infonode.subptr:=aNode.SubDirRVA; 182 end; 183 fRelocations.Add( 184 fCurOfs+sizeof(infonode.nameid)+sizeof(infonode.ncount)+ 185 sizeof(infonode.idcountsize),ffpcresourcessym); 186 if fOppositeEndianess then 187 begin 188 infonode.nameid:=SwapEndian(infonode.nameid); 189 infonode.ncount:=SwapEndian(infonode.ncount); 190 infonode.idcountsize:=SwapEndian(infonode.idcountsize); 191 infonode.subptr:=SwapEndian(infonode.subptr); 192 end; 193 aStream.WriteBuffer(infonode,sizeof(infonode)); 194 inc(fCurOfs,sizeof(infonode)); 195end; 196 197procedure _TMachOSubWriter_.AllocateSpaceForLoadCommands(aStream: TStream); 198var buf : pbyte; 199begin 200 fHeader.sizeofcmds:= 201 //segment+res section+bss section 202 sizeof(_TSegmentCommand_)+sizeof(_TSection_)*3+ 203 //symbol table and dynamic symbol table commands 204 sizeof(TSymtabCommand)+sizeof(TDySymtabCommand)+ 205 //common header of the three commands 206 sizeof(TLoadCommand)*3; 207 buf:=GetMem(fHeader.sizeofcmds); 208 FillByte(buf^,fHeader.sizeofcmds,0); 209 try 210 aStream.WriteBuffer(buf^,fHeader.sizeofcmds); 211 finally 212 FreeMem(buf); 213 end; 214end; 215 216procedure _TMachOSubWriter_.FixLoadCommands(aStream: TStream; aResources : TResources); 217var ldcommand : TLoadCommand; 218 segcommand : _TSegmentCommand_; 219 symcommand : TSymtabCommand; 220 dysymcommand : TDySymtabCommand; 221 ressection,bsssection,textsection : _TSection_; 222begin 223 ldcommand.cmd:=fSegType; 224 ldcommand.cmdsize:=sizeof(TLoadCommand)+sizeof(segcommand)+sizeof(ressection)*3; 225 226 FillByte(segcommand.name[0],16,0); 227 segcommand.vmaddr:=0; 228 segcommand.vmsize:=fDataCurOfs+sizeof(_ptrtype_)*aResources.Count; 229 segcommand.fileoff:=fSectionStart; 230 segcommand.filesize:=fDataCurOfs; 231 segcommand.maxprot:=VM_PROT_READ or VM_PROT_WRITE or VM_PROT_EXECUTE; 232 segcommand.initprot:=VM_PROT_READ or VM_PROT_WRITE or VM_PROT_EXECUTE; 233 segcommand.nsects:=3; 234 segcommand.flags:=0; 235 236 fillbyte(textsection,sizeof(textsection),0); 237 textsection.sectname:='__text'; 238 textsection.segname:='__TEXT'; 239 textsection.addr:=0; 240 textsection.size:=0; 241 textsection.offset:=segcommand.fileoff; 242 textsection.align:=0; 243 textsection.reloff:=0; 244 textsection.nreloc:=0; 245 textsection.flags:=S_ATTR_PURE_INSTRUCTIONS; 246 textsection.reserved1:=0; 247 textsection.reserved2:=0; 248 249 fillbyte(ressection,sizeof(ressection),0); 250 ressection.sectname:=RsrcSectName; 251 ressection.segname:=DataSegName; 252 ressection.addr:=0; 253 ressection.size:=segcommand.filesize; 254 ressection.offset:=segcommand.fileoff; 255 ressection.align:=fSectAlignment; 256 ressection.reloff:=fRelocations.StartOfs; 257 ressection.nreloc:=fRelocations.Count; 258 ressection.flags:=S_ATTR_LOC_RELOC; 259 ressection.reserved1:=0; 260 ressection.reserved2:=0; 261 262 fillbyte(bsssection,sizeof(bsssection),0); 263 bsssection.sectname:=HandlesSectName; 264 bsssection.segname:=DataSegName; 265 bsssection.addr:=fDataCurOfs; 266 bsssection.size:=sizeof(_ptrtype_)*aResources.Count; 267 bsssection.offset:=0; 268 bsssection.align:=fSectAlignment; 269 bsssection.reloff:=0; 270 bsssection.nreloc:=0; 271 bsssection.flags:=S_ZEROFILL; 272 bsssection.reserved1:=0; 273 bsssection.reserved2:=0; 274 275 if fOppositeEndianess then 276 begin 277 ldcommand.cmd:=SwapEndian(ldcommand.cmd); 278 ldcommand.cmdsize:=SwapEndian(ldcommand.cmdsize); 279 280 segcommand.vmaddr:=SwapEndian(segcommand.vmaddr); 281 segcommand.vmsize:=SwapEndian(segcommand.vmsize); 282 segcommand.fileoff:=SwapEndian(segcommand.fileoff); 283 segcommand.filesize:=SwapEndian(segcommand.filesize); 284 segcommand.maxprot:=SwapEndian(segcommand.maxprot); 285 segcommand.initprot:=SwapEndian(segcommand.initprot); 286 segcommand.nsects:=SwapEndian(segcommand.nsects); 287 segcommand.flags:=SwapEndian(segcommand.flags); 288 289 SwapSection(textsection); 290 SwapSection(ressection); 291 SwapSection(bsssection); 292 end; 293 294 aStream.WriteBuffer(ldcommand,sizeof(ldcommand)); 295 aStream.WriteBuffer(segcommand,sizeof(segcommand)); 296 aStream.WriteBuffer(textsection,sizeof(textsection)); 297 aStream.WriteBuffer(ressection,sizeof(ressection)); 298 aStream.WriteBuffer(bsssection,sizeof(bsssection)); 299 300 ldcommand.cmd:=LC_SYMTAB; 301 ldcommand.cmdsize:=sizeof(TLoadCommand)+sizeof(symcommand); 302 303 symcommand.symoff:=fSymbolTable.StartOfs; 304 symcommand.nsyms:=fSymbolTable.Count; 305 symcommand.stroff:=fMachOStringTable.StartOfs; 306 symcommand.strsize:=NextAligned(4,fMachOStringTable.Size); 307 308 if fOppositeEndianess then 309 begin 310 ldcommand.cmd:=SwapEndian(ldcommand.cmd); 311 ldcommand.cmdsize:=SwapEndian(ldcommand.cmdsize); 312 313 symcommand.symoff:=SwapEndian(symcommand.symoff); 314 symcommand.nsyms:=SwapEndian(symcommand.nsyms); 315 symcommand.stroff:=SwapEndian(symcommand.stroff); 316 symcommand.strsize:=SwapEndian(symcommand.strsize); 317 end; 318 319 aStream.WriteBuffer(ldcommand,sizeof(ldcommand)); 320 aStream.WriteBuffer(symcommand,sizeof(symcommand)); 321 322 ldcommand.cmd:=LC_DYSYMTAB; 323 ldcommand.cmdsize:=sizeof(TLoadCommand)+sizeof(dysymcommand); 324 325 dysymcommand.ilocalsym:=0; 326 dysymcommand.nlocalsym:=fSymbolTable.LocalCount; 327 dysymcommand.iextdefsym:=dysymcommand.ilocalsym+dysymcommand.nlocalsym; 328 dysymcommand.nextdefsym:=fSymbolTable.GlobalCount; 329 dysymcommand.iundefsym:=dysymcommand.iextdefsym+dysymcommand.nextdefsym; 330 dysymcommand.nundefsym:=0; 331 dysymcommand.tocoff:=0; 332 dysymcommand.ntoc:=0; 333 dysymcommand.modtaboff:=0; 334 dysymcommand.nmodtab:=0; 335 dysymcommand.extrefsymoff:=0; 336 dysymcommand.nextrefsyms:=0; 337 dysymcommand.indirectsymoff:=0; 338 dysymcommand.nindirectsyms:=0; 339 dysymcommand.extreloff:=0; 340 dysymcommand.nextrel:=0; 341 dysymcommand.locreloff:=0; 342 dysymcommand.nlocrel:=0; 343 344 if fOppositeEndianess then 345 begin 346 ldcommand.cmd:=SwapEndian(ldcommand.cmd); 347 ldcommand.cmdsize:=SwapEndian(ldcommand.cmdsize); 348 349 dysymcommand.ilocalsym:=SwapEndian(dysymcommand.ilocalsym); 350 dysymcommand.nlocalsym:=SwapEndian(dysymcommand.nlocalsym); 351 dysymcommand.iextdefsym:=SwapEndian(dysymcommand.iextdefsym); 352 dysymcommand.nextdefsym:=SwapEndian(dysymcommand.nextdefsym); 353 dysymcommand.iundefsym:=SwapEndian(dysymcommand.iundefsym); 354 dysymcommand.nundefsym:=SwapEndian(dysymcommand.nundefsym); 355 dysymcommand.tocoff:=SwapEndian(dysymcommand.tocoff); 356 dysymcommand.ntoc:=SwapEndian(dysymcommand.ntoc); 357 dysymcommand.modtaboff:=SwapEndian(dysymcommand.modtaboff); 358 dysymcommand.nmodtab:=SwapEndian(dysymcommand.nmodtab); 359 dysymcommand.extrefsymoff:=SwapEndian(dysymcommand.extrefsymoff); 360 dysymcommand.nextrefsyms:=SwapEndian(dysymcommand.nextrefsyms); 361 dysymcommand.indirectsymoff:=SwapEndian(dysymcommand.indirectsymoff); 362 dysymcommand.nindirectsyms:=SwapEndian(dysymcommand.nindirectsyms); 363 dysymcommand.extreloff:=SwapEndian(dysymcommand.extreloff); 364 dysymcommand.nextrel:=SwapEndian(dysymcommand.nextrel); 365 dysymcommand.locreloff:=SwapEndian(dysymcommand.locreloff); 366 dysymcommand.nlocrel:=SwapEndian(dysymcommand.nlocrel); 367 end; 368 369 aStream.WriteBuffer(ldcommand,sizeof(ldcommand)); 370 aStream.WriteBuffer(dysymcommand,sizeof(dysymcommand)); 371end; 372 373constructor _TMachOSubWriter_.Create(aParent : TMachOResourceWriter; 374 const aMachineType : TMachOMachineType; const aSubMachineType: TMachoSubMachineType; const aOppositeEndianess : boolean); 375begin 376 inherited Create(aParent,aMachineType,aSubMachineType,aOppositeEndianess); 377 fSymbolTable:=_TMachOSymbolTable_.Create(fMachOStringTable); 378 fSymbolTable.OppositeEndianess:=fOppositeEndianess; 379 {$IF _TMachOSubWriter_=TMachO32SubWriter} 380 fDataAlignment:=4; 381 fSectAlignment:=2; //2^2 382 fSegType:=LC_SEGMENT; 383 {$ELSE} 384 fDataAlignment:=8; 385 fSectAlignment:=3; //2^3 386 fSegType:=LC_SEGMENT_64; 387 {$ENDIF} 388end; 389 390