1/* 2 Title: Write out a database as a Mach object file 3 Author: David Matthews. 4 5 Copyright (c) 2006-7, 2011-2, 2016 David C. J. Matthews 6 7 This library is free software; you can redistribute it and/or 8 modify it under the terms of the GNU Lesser General Public 9 License version 2.1 as published by the Free Software Foundation. 10 11 This library is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR H PARTICULAR PURPOSE. See the GNU 14 Lesser General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public 17 License along with this library; if not, write to the Free Software 18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 19*/ 20 21#include "config.h" 22 23#ifdef HAVE_STDLIB_H 24#include <stdlib.h> 25#endif 26 27#ifdef HAVE_STDIO_H 28#include <stdio.h> 29#endif 30 31#ifdef HAVE_STDDEF_H 32#include <stddef.h> 33#endif 34 35#ifdef HAVE_UNISTD_H 36#include <unistd.h> 37#endif 38 39#ifdef HAVE_ERRNO_H 40#include <errno.h> 41#endif 42 43#ifdef HAVE_TIME_H 44#include <time.h> 45#endif 46 47#ifdef HAVE_ASSERT_H 48#include <assert.h> 49#define ASSERT(x) assert(x) 50#else 51#define ASSERT(x) 52#endif 53 54// If we haven't got the Mach header files we shouldn't be building this. 55#include <mach-o/loader.h> 56#include <mach-o/reloc.h> 57#include <mach-o/nlist.h> 58#include <mach-o/ppc/reloc.h> 59#include <mach-o/x86_64/reloc.h> 60 61#ifdef HAVE_STRING_H 62#include <string.h> 63#endif 64#ifdef HAVE_SYS_UTSNAME_H 65#include <sys/utsname.h> 66#endif 67 68#include "globals.h" 69 70#include "diagnostics.h" 71#include "sys.h" 72#include "machine_dep.h" 73#include "gc.h" 74#include "mpoly.h" 75#include "scanaddrs.h" 76#include "machoexport.h" 77#include "run_time.h" 78#include "version.h" 79#include "polystring.h" 80#include "timing.h" 81 82// Mach-O seems to require each section to have a discrete virtual address range 83// so we have to adjust various offsets to fit. 84void MachoExport::adjustOffset(unsigned area, POLYUNSIGNED &offset) 85{ 86 // Add in the offset. If sect is memTableEntries it's actually the 87 // descriptors so doesn't have any additional offset. 88 if (area != memTableEntries) 89 { 90 offset += sizeof(exportDescription)+sizeof(memoryTableEntry)*memTableEntries; 91 for (unsigned i = 0; i < area; i++) 92 offset += memTable[i].mtLength; 93 } 94} 95 96void MachoExport::addExternalReference(void *relocAddr, const char *name, bool /*isFuncPtr*/) 97{ 98 externTable.makeEntry(name); 99 writeRelocation(0, relocAddr, symbolNum++, true); 100} 101 102// Generate the address relative to the start of the segment. 103void MachoExport::setRelocationAddress(void *p, int32_t *reloc) 104{ 105 unsigned area = findArea(p); 106 POLYUNSIGNED offset = (char*)p - (char*)memTable[area].mtAddr; 107 *reloc = offset; 108} 109 110/* Get the index corresponding to an address. */ 111PolyWord MachoExport::createRelocation(PolyWord p, void *relocAddr) 112{ 113 void *addr = p.AsAddress(); 114 unsigned addrArea = findArea(addr); 115 POLYUNSIGNED offset = (char*)addr - (char*)memTable[addrArea].mtAddr; 116 adjustOffset(addrArea, offset); 117 return writeRelocation(offset, relocAddr, addrArea+1 /* Sections count from 1 */, false); 118} 119 120PolyWord MachoExport::writeRelocation(POLYUNSIGNED offset, void *relocAddr, unsigned symbolNumber, bool isExtern) 121{ 122 // It looks as though struct relocation_info entries are only used 123 // with GENERIC_RELOC_VANILLA types. 124 struct relocation_info relInfo; 125 setRelocationAddress(relocAddr, &relInfo.r_address); 126 relInfo.r_symbolnum = symbolNumber; 127 relInfo.r_pcrel = 0; 128#if (SIZEOF_VOIDP == 8) 129 relInfo.r_length = 3; // 8 bytes 130 relInfo.r_type = X86_64_RELOC_UNSIGNED; 131#else 132 relInfo.r_length = 2; // 4 bytes 133 relInfo.r_type = GENERIC_RELOC_VANILLA; 134#endif 135 relInfo.r_extern = isExtern ? 1 : 0; 136 137 fwrite(&relInfo, sizeof(relInfo), 1, exportFile); 138 relocationCount++; 139 return PolyWord::FromUnsigned(offset); 140} 141 142/* This is called for each constant within the code. 143 Print a relocation entry for the word and return a value that means 144 that the offset is saved in original word. */ 145void MachoExport::ScanConstant(PolyObject *base, byte *addr, ScanRelocationKind code) 146{ 147 PolyWord p = GetConstantValue(addr, code); 148 149 if (IS_INT(p) || p == PolyWord::FromUnsigned(0)) 150 return; 151 152 void *a = p.AsAddress(); 153 unsigned aArea = findArea(a); 154 155 // Set the value at the address to the offset relative to the symbol. 156 POLYUNSIGNED offset = (char*)a - (char*)memTable[aArea].mtAddr; 157 adjustOffset(aArea, offset); 158 159 switch (code) 160 { 161 case PROCESS_RELOC_DIRECT: // 32 bit address of target 162 { 163 struct relocation_info reloc; 164 setRelocationAddress(addr, &reloc.r_address); 165 reloc.r_symbolnum = aArea+1; // Section numbers start at 1 166 reloc.r_pcrel = 0; 167#if (defined(HOSTARCHITECTURE_X86_64)) 168 reloc.r_length = 3; // 8 bytes 169 reloc.r_type = X86_64_RELOC_UNSIGNED; 170#else 171 reloc.r_length = 2; // 4 bytes 172 reloc.r_type = GENERIC_RELOC_VANILLA; 173#endif 174 reloc.r_extern = 0; // r_symbolnum is a section number. It should be 1 if we make the IO area a common. 175 176 for (unsigned i = 0; i < sizeof(PolyWord); i++) 177 { 178 addr[i] = (byte)(offset & 0xff); 179 offset >>= 8; 180 } 181 fwrite(&reloc, sizeof(reloc), 1, exportFile); 182 relocationCount++; 183 } 184 break; 185#if (defined(HOSTARCHITECTURE_X86) || defined(HOSTARCHITECTURE_X86_64)) 186 case PROCESS_RELOC_I386RELATIVE: // 32 bit relative address 187 { 188 unsigned addrArea = findArea(addr); 189 // If it's in the same area we don't need a relocation because the 190 // relative offset will be unchanged. 191 if (addrArea != aArea) 192 { 193 struct relocation_info reloc; 194 setRelocationAddress(addr, &reloc.r_address); 195 reloc.r_symbolnum = aArea+1; // Section numbers start at 1 196 reloc.r_pcrel = 1; 197 reloc.r_length = 2; // 4 bytes 198#if (defined(HOSTARCHITECTURE_X86_64)) 199 reloc.r_type = X86_64_RELOC_SIGNED; 200#else 201 reloc.r_type = GENERIC_RELOC_VANILLA; 202#endif 203 reloc.r_extern = 0; // r_symbolnum is a section number. 204 fwrite(&reloc, sizeof(reloc), 1, exportFile); 205 relocationCount++; 206 207 POLYUNSIGNED addrOffset = (char*)addr - (char*)memTable[addrArea].mtAddr; 208 adjustOffset(addrArea, addrOffset); 209 offset -= addrOffset + 4; 210 211 for (unsigned i = 0; i < 4; i++) 212 { 213 addr[i] = (byte)(offset & 0xff); 214 offset >>= 8; 215 } 216 } 217 } 218 break; 219#endif 220 default: 221 ASSERT(0); // Wrong type of relocation for this architecture. 222 } 223} 224 225// Set the file alignment. 226void MachoExport::alignFile(int align) 227{ 228 char pad[32] = {0}; // Maximum alignment 229 int offset = ftell(exportFile); 230 if ((offset % align) == 0) return; 231 fwrite(&pad, align - (offset % align), 1, exportFile); 232} 233 234void MachoExport::createStructsRelocation(unsigned sect, POLYUNSIGNED offset) 235{ 236 struct relocation_info reloc; 237 reloc.r_address = offset; 238 reloc.r_symbolnum = sect+1; // Section numbers start at 1 239 reloc.r_pcrel = 0; 240#if (SIZEOF_VOIDP == 8) 241 reloc.r_length = 3; // 8 bytes 242 reloc.r_type = X86_64_RELOC_UNSIGNED; 243#else 244 reloc.r_length = 2; // 4 bytes 245 reloc.r_type = GENERIC_RELOC_VANILLA; 246#endif 247 reloc.r_extern = 0; // r_symbolnum is a section number. 248 249 fwrite(&reloc, sizeof(reloc), 1, exportFile); 250 relocationCount++; 251} 252 253void MachoExport::exportStore(void) 254{ 255 PolyWord *p; 256#if (SIZEOF_VOIDP == 8) 257 struct mach_header_64 fhdr; 258 struct segment_command_64 sHdr; 259 struct section_64 *sections = new section_64[memTableEntries+1]; 260 size_t sectionSize = sizeof(section_64); 261#else 262 struct mach_header fhdr; 263 struct segment_command sHdr; 264 struct section *sections = new section[memTableEntries+1]; 265 size_t sectionSize = sizeof(section); 266#endif 267 struct symtab_command symTab; 268 unsigned i; 269 270 // Write out initial values for the headers. These are overwritten at the end. 271 // File header 272 memset(&fhdr, 0, sizeof(fhdr)); 273 fhdr.filetype = MH_OBJECT; 274 fhdr.ncmds = 2; // One for the segment and one for the symbol table. 275 fhdr.sizeofcmds = sizeof(sHdr) + sectionSize * (memTableEntries+1) + sizeof(symTab); 276 fhdr.flags = 0; 277 // The machine needs to match the machine we're compiling for 278 // even if this is actually portable code. 279#if (SIZEOF_VOIDP == 8) 280 fhdr.magic = MH_MAGIC_64; // (0xfeedfacf) 64-bit magic number 281#else 282 fhdr.magic = MH_MAGIC; // Feed Face (0xfeedface) 283#endif 284#if defined(HOSTARCHITECTURE_X86) 285 fhdr.cputype = CPU_TYPE_I386; 286 fhdr.cpusubtype = CPU_SUBTYPE_I386_ALL; 287#elif defined(HOSTARCHITECTURE_PPC) 288 fhdr.cputype = CPU_TYPE_POWERPC; 289 fhdr.cpusubtype = CPU_SUBTYPE_POWERPC_ALL; 290#elif defined(HOSTARCHITECTURE_X86_64) 291 fhdr.cputype = CPU_TYPE_X86_64; 292 fhdr.cpusubtype = CPU_SUBTYPE_X86_64_ALL; 293#else 294#error "No support for exporting on this architecture" 295#endif 296 fwrite(&fhdr, sizeof(fhdr), 1, exportFile); // Write it for the moment. 297 298 symbolNum = 1; // The first symbol is poly_exports 299 300 // Segment header. 301 memset(&sHdr, 0, sizeof(sHdr)); 302#if (SIZEOF_VOIDP == 8) 303 sHdr.cmd = LC_SEGMENT_64; 304#else 305 sHdr.cmd = LC_SEGMENT; 306#endif 307 sHdr.nsects = memTableEntries+1; // One for each entry plus one for the tables. 308 sHdr.cmdsize = sizeof(sHdr) + sectionSize * sHdr.nsects; 309 // Add up the sections to give the file size 310 sHdr.filesize = 0; 311 for (i = 0; i < memTableEntries; i++) 312 sHdr.filesize += memTable[i].mtLength; // Do we need any alignment? 313 sHdr.filesize += sizeof(exportDescription) + memTableEntries * sizeof(memoryTableEntry); 314 sHdr.vmsize = sHdr.filesize; // Set them the same since we don't have any "common" area. 315 // sHdr.fileOff is set later. 316 sHdr.maxprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE; 317 sHdr.initprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE; 318 sHdr.flags = 0; 319 320 // Write it initially. 321 fwrite(&sHdr, sizeof(sHdr), 1, exportFile); 322 323 // Section header for each entry in the table 324 POLYUNSIGNED sectAddr = sizeof(exportDescription)+sizeof(memoryTableEntry)*memTableEntries; 325 for (i = 0; i < memTableEntries; i++) 326 { 327 memset(&(sections[i]), 0, sectionSize); 328 329 if (memTable[i].mtFlags & MTF_WRITEABLE) 330 { 331 // Mutable areas 332 ASSERT(!(memTable[i].mtFlags & MTF_EXECUTABLE)); // Executable areas can't be writable. 333 sprintf(sections[i].sectname, "__data"); 334 sprintf(sections[i].segname, "__DATA"); 335 sections[i].flags = S_ATTR_LOC_RELOC | S_REGULAR; 336 } 337 else if (memTable[i].mtFlags & MTF_EXECUTABLE) 338 { 339 sprintf(sections[i].sectname, "__text"); 340 sprintf(sections[i].segname, "__TEXT"); 341 sections[i].flags = S_ATTR_LOC_RELOC | S_ATTR_SOME_INSTRUCTIONS | S_REGULAR; 342 } 343 else 344 { 345 sprintf(sections[i].sectname, "__const"); 346 sprintf(sections[i].segname, "__DATA"); 347 sections[i].flags = S_ATTR_LOC_RELOC | S_REGULAR; 348 } 349 350 sections[i].addr = sectAddr; 351 sections[i].size = memTable[i].mtLength; 352 sectAddr += memTable[i].mtLength; 353 //sections[i].offset is set later 354 //sections[i].reloff is set later 355 //sections[i].nreloc is set later 356 sections[i].align = 3; // 8 byte alignment 357 // theSection.size is set later 358 359 } 360 // For the tables. 361 memset(&(sections[memTableEntries]), 0, sectionSize); 362 sprintf(sections[memTableEntries].sectname, "__const"); 363 sprintf(sections[memTableEntries].segname, "__DATA"); 364 sections[memTableEntries].addr = 0; 365 sections[memTableEntries].size = sizeof(exportDescription)+sizeof(memoryTableEntry)*memTableEntries; 366 sections[memTableEntries].align = 3; // 8 byte alignment 367 // theSection.size is set later 368 sections[memTableEntries].flags = S_ATTR_LOC_RELOC | S_ATTR_SOME_INSTRUCTIONS | S_REGULAR; 369 370 // Write them out for the moment. 371 fwrite(sections, sectionSize * (memTableEntries+1), 1, exportFile); 372 373 // Symbol table header. 374 memset(&symTab, 0, sizeof(symTab)); 375 symTab.cmd = LC_SYMTAB; 376 symTab.cmdsize = sizeof(symTab); 377 //symTab.symoff is set later 378 //symTab.nsyms is set later 379 //symTab.stroff is set later 380 //symTab.strsize is set later 381 fwrite(&symTab, sizeof(symTab), 1, exportFile); 382 383 // Create and write out the relocations. 384 for (i = 0; i < memTableEntries; i++) 385 { 386 sections[i].reloff = ftell(exportFile); 387 relocationCount = 0; 388 // Create the relocation table and turn all addresses into offsets. 389 char *start = (char*)memTable[i].mtAddr; 390 char *end = start + memTable[i].mtLength; 391 for (p = (PolyWord*)start; p < (PolyWord*)end; ) 392 { 393 p++; 394 PolyObject *obj = (PolyObject*)p; 395 POLYUNSIGNED length = obj->Length(); 396 if (length != 0 && obj->IsCodeObject()) 397 machineDependent->ScanConstantsWithinCode(obj, this); 398 relocateObject(obj); 399 p += length; 400 } 401 sections[i].nreloc = relocationCount; 402 } 403 404 // Additional relocations for the descriptors. 405 sections[memTableEntries].reloff = ftell(exportFile); 406 relocationCount = 0; 407 408 // Address of "memTable" within "exports". We can't use createRelocation because 409 // the position of the relocation is not in either the mutable or the immutable area. 410 createStructsRelocation(memTableEntries, offsetof(exportDescription, memTable)); 411 412 // Address of "rootFunction" within "exports" 413 unsigned rootAddrArea = findArea(rootFunction); 414 POLYUNSIGNED rootOffset = (char*)rootFunction - (char*)memTable[rootAddrArea].mtAddr; 415 adjustOffset(rootAddrArea, rootOffset); 416 createStructsRelocation(rootAddrArea, offsetof(exportDescription, rootFunction)); 417 418 // Addresses of the areas within memtable. 419 for (i = 0; i < memTableEntries; i++) 420 { 421 createStructsRelocation(i, 422 sizeof(exportDescription) + i * sizeof(memoryTableEntry) + offsetof(memoryTableEntry, mtAddr)); 423 } 424 sections[memTableEntries].nreloc = relocationCount; 425 426 // The symbol table. 427 428 symTab.symoff = ftell(exportFile); 429 // Global symbols: Just one. 430 { 431#if (SIZEOF_VOIDP == 8) 432 struct nlist_64 symbol; 433#else 434 struct nlist symbol; 435#endif 436 memset(&symbol, 0, sizeof(symbol)); // Zero unused fields 437 symbol.n_un.n_strx = stringTable.makeEntry("_poly_exports"); 438 symbol.n_type = N_EXT | N_SECT; 439 symbol.n_sect = memTableEntries+1; // Sections count from 1. 440 symbol.n_desc = REFERENCE_FLAG_DEFINED; 441 fwrite(&symbol, sizeof(symbol), 1, exportFile); 442 } 443 444 // External references. 445 for (unsigned i = 0; i < externTable.stringSize; i += (unsigned)strlen(externTable.strings+i) + 1) 446 { 447 const char *symbolName = externTable.strings+i; 448#if (SIZEOF_VOIDP == 8) 449 struct nlist_64 symbol; 450#else 451 struct nlist symbol; 452#endif 453 memset(&symbol, 0, sizeof(symbol)); // Zero unused fields 454 // Have to add an underscore to the symbols. 455 TempCString fullSymbol; 456 fullSymbol = (char*)malloc(strlen(symbolName) + 2); 457 if (fullSymbol == 0) throw MemoryException(); 458 sprintf(fullSymbol, "_%s", symbolName); 459 symbol.n_un.n_strx = stringTable.makeEntry(fullSymbol); 460 symbol.n_type = N_EXT | N_UNDF; 461 symbol.n_sect = NO_SECT; 462 symbol.n_desc = REFERENCE_FLAG_UNDEFINED_NON_LAZY; 463 fwrite(&symbol, sizeof(symbol), 1, exportFile); 464 } 465 466 symTab.nsyms = symbolNum; 467 468 // The symbol name table 469 symTab.stroff = ftell(exportFile); 470 fwrite(stringTable.strings, stringTable.stringSize, 1, exportFile); 471 symTab.strsize = stringTable.stringSize; 472 alignFile(4); 473 474 exportDescription exports; 475 memset(&exports, 0, sizeof(exports)); 476 exports.structLength = sizeof(exportDescription); 477 exports.memTableSize = sizeof(memoryTableEntry); 478 exports.memTableEntries = memTableEntries; 479 exports.memTable = (memoryTableEntry *)sizeof(exportDescription); // It follows immediately after this. 480 // Set the value to be the offset relative to the base of the area. We have set a relocation 481 // already which will add the base of the area. 482 exports.rootFunction = (void*)rootOffset; 483 exports.timeStamp = getBuildTime(); 484 exports.architecture = machineDependent->MachineArchitecture(); 485 exports.rtsVersion = POLY_version_number; 486 487 sections[memTableEntries].offset = ftell(exportFile); 488 fwrite(&exports, sizeof(exports), 1, exportFile); 489 POLYUNSIGNED addrOffset = sizeof(exports)+sizeof(memoryTableEntry)*memTableEntries; 490 for (i = 0; i < memTableEntries; i++) 491 { 492 void *save = memTable[i].mtAddr; 493 memTable[i].mtAddr = (void*)addrOffset; // Set this to the relative address. 494 addrOffset += memTable[i].mtLength; 495 fwrite(&memTable[i], sizeof(memoryTableEntry), 1, exportFile); 496 memTable[i].mtAddr = save; 497 } 498 499 // Now the binary data. 500 for (i = 0; i < memTableEntries; i++) 501 { 502 alignFile(4); 503 sections[i].offset = ftell(exportFile); 504 fwrite(memTable[i].mtAddr, 1, memTable[i].mtLength, exportFile); 505 } 506 // Rewind to rewrite the headers with the actual offsets. 507 rewind(exportFile); 508 fwrite(&fhdr, sizeof(fhdr), 1, exportFile); // File header 509 fwrite(&sHdr, sizeof(sHdr), 1, exportFile); // Segment header 510 fwrite(sections, sectionSize * (memTableEntries+1), 1, exportFile); // Section headers 511 fwrite(&symTab, sizeof(symTab), 1, exportFile); // Symbol table header 512 fclose(exportFile); exportFile = NULL; 513 514 delete[](sections); 515} 516