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