Exemplo n.º 1
0
void MachoExport::exportStore(void)
{
    PolyWord    *p;
#if (SIZEOF_VOIDP == 8)
    struct mach_header_64 fhdr;
    struct segment_command_64 sHdr;
    struct section_64 *sections = new section_64[memTableEntries+1];
    size_t sectionSize = sizeof(section_64);
#else
    struct mach_header fhdr;
    struct segment_command sHdr;
    struct section *sections = new section[memTableEntries+1];
    size_t sectionSize = sizeof(section);
#endif
    struct symtab_command symTab;
    unsigned i;

    // Write out initial values for the headers.  These are overwritten at the end.
    // File header
    memset(&fhdr, 0, sizeof(fhdr));
    fhdr.filetype = MH_OBJECT;
    fhdr.ncmds = 2; // One for the segment and one for the symbol table.
    fhdr.sizeofcmds = sizeof(sHdr) + sectionSize * (memTableEntries+1) + sizeof(symTab);
    fhdr.flags = 0;
    // The machine needs to match the machine we're compiling for
    // even if this is actually portable code.
#if (SIZEOF_VOIDP == 8)
    fhdr.magic = MH_MAGIC_64; // (0xfeedfacf) 64-bit magic number
#else
    fhdr.magic = MH_MAGIC; // Feed Face (0xfeedface)
#endif
#if defined(HOSTARCHITECTURE_X86)
    fhdr.cputype = CPU_TYPE_I386;
    fhdr.cpusubtype = CPU_SUBTYPE_I386_ALL;
#elif defined(HOSTARCHITECTURE_PPC)
    fhdr.cputype = CPU_TYPE_POWERPC;
    fhdr.cpusubtype = CPU_SUBTYPE_POWERPC_ALL;
#elif defined(HOSTARCHITECTURE_X86_64)
    fhdr.cputype = CPU_TYPE_X86_64;
    fhdr.cpusubtype = CPU_SUBTYPE_X86_64_ALL;
#else
#error "No support for exporting on this architecture"
#endif
    fwrite(&fhdr, sizeof(fhdr), 1, exportFile); // Write it for the moment.

    // Segment header.
    memset(&sHdr, 0, sizeof(sHdr));
#if (SIZEOF_VOIDP == 8)
    sHdr.cmd = LC_SEGMENT_64;
#else
    sHdr.cmd = LC_SEGMENT;
#endif
    sHdr.nsects = memTableEntries+1; // One for each entry plus one for the tables.
    sHdr.cmdsize = sizeof(sHdr) + sectionSize * sHdr.nsects;
    // Add up the sections to give the file size
    sHdr.filesize = 0;
    for (i = 0; i < memTableEntries; i++)
        sHdr.filesize += memTable[i].mtLength; // Do we need any alignment?
    sHdr.filesize += sizeof(exportDescription) + memTableEntries * sizeof(memoryTableEntry);
    sHdr.vmsize = sHdr.filesize; // Set them the same since we don't have any "common" area.
    // sHdr.fileOff is set later.
    sHdr.maxprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
    sHdr.initprot = VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE;
    sHdr.flags = 0;

    // Write it initially.
    fwrite(&sHdr, sizeof(sHdr), 1, exportFile);

    // Section header for each entry in the table
    POLYUNSIGNED sectAddr = sizeof(exportDescription)+sizeof(memoryTableEntry)*memTableEntries;
    for (i = 0; i < memTableEntries; i++)
    {
        memset(&(sections[i]), 0, sectionSize);

        if (memTable[i].mtFlags & MTF_WRITEABLE)
        {
            // Mutable areas
            ASSERT(!(memTable[i].mtFlags & MTF_EXECUTABLE)); // Executable areas can't be writable.
            sprintf(sections[i].sectname, "__data");
            sprintf(sections[i].segname, "__DATA");
            sections[i].flags = S_ATTR_LOC_RELOC | S_REGULAR;
        }
        else if (memTable[i].mtFlags & MTF_EXECUTABLE)
        {
            sprintf(sections[i].sectname, "__text");
            sprintf(sections[i].segname, "__TEXT");
            sections[i].flags = S_ATTR_LOC_RELOC | S_ATTR_SOME_INSTRUCTIONS | S_REGULAR;
        }
        else
        {
            sprintf(sections[i].sectname, "__const");
            sprintf(sections[i].segname, "__DATA");
            sections[i].flags = S_ATTR_LOC_RELOC | S_REGULAR;
        }

        sections[i].addr = sectAddr;
        sections[i].size = memTable[i].mtLength;
        sectAddr += memTable[i].mtLength;
        //sections[i].offset is set later
        //sections[i].reloff is set later
        //sections[i].nreloc is set later
        sections[i].align = 3; // 8 byte alignment
        // theSection.size is set later

    }
    // For the tables.
    memset(&(sections[memTableEntries]), 0, sectionSize);
    sprintf(sections[memTableEntries].sectname, "__const");
    sprintf(sections[memTableEntries].segname, "__DATA");
    sections[memTableEntries].addr = 0;
    sections[memTableEntries].size = sizeof(exportDescription)+sizeof(memoryTableEntry)*memTableEntries;
    sections[memTableEntries].align = 3; // 8 byte alignment
    // theSection.size is set later
    sections[memTableEntries].flags = S_ATTR_LOC_RELOC | S_ATTR_SOME_INSTRUCTIONS | S_REGULAR;

    // Write them out for the moment.
    fwrite(sections, sectionSize * (memTableEntries+1), 1, exportFile);

    // Symbol table header.
    memset(&symTab, 0, sizeof(symTab));
    symTab.cmd = LC_SYMTAB;
    symTab.cmdsize = sizeof(symTab);
    //symTab.symoff is set later
    //symTab.nsyms is set later
    //symTab.stroff is set later
    //symTab.strsize is set later
    fwrite(&symTab, sizeof(symTab), 1, exportFile);

    // Create the symbol table first before we mess up the addresses by turning them
    // into relocations.
    symTab.symoff = ftell(exportFile);
    // Global symbols: Just one.  Mach prefixes symbols with an underscore.
    writeSymbol("_poly_exports", N_EXT | N_SECT, memTableEntries, 0); // The export table comes first
    // We create local symbols because they make debugging easier.  They may also
    // mean that we can use the usual Unix profiling tools.
    writeSymbol("memTable", N_SECT, memTableEntries, sizeof(exportDescription)); // Then the memTable.
    for (i = 0; i < memTableEntries; i++)
    {
        if (i == ioMemEntry)
            writeSymbol("ioarea", N_SECT, i, 0);
        else {
            char buff[50];
            sprintf(buff, "area%0d", i);
            writeSymbol(buff, N_SECT, i, 0);
#if (SIZEOF_VOIDP == 8)
            // See if we can find the names of any functions.
            // This seems to break on 32-bit Mac OS X.  It seems to align
            // some relocations onto an 8-byte boundary so we just disable it.
            char *start = (char*)memTable[i].mtAddr;
            char *end = start + memTable[i].mtLength;
            for (p = (PolyWord*)start; p < (PolyWord*)end; )
            {
                p++;
                PolyObject *obj = (PolyObject*)p;
                POLYUNSIGNED length = obj->Length();
                if (length != 0 && obj->IsCodeObject())
                {
                    PolyWord *name = obj->ConstPtrForCode();
                    // Copy as much of the name as will fit and ignore any extra.
                    // Do we need to worry about duplicates?
                    (void)Poly_string_to_C(*name, buff, sizeof(buff));
                    writeSymbol(buff, N_SECT, i, (char*)p - start);
                }
                p += length;
            }
#endif
        }
    }
    symTab.nsyms = symbolCount;

    // Create and write out the relocations.
    for (i = 0; i < memTableEntries; i++)
    {
        sections[i].reloff = ftell(exportFile);
        relocationCount = 0;
        if (i != ioMemEntry) // Don't relocate the IO area
        {
            // Create the relocation table and turn all addresses into offsets.
            char *start = (char*)memTable[i].mtAddr;
            char *end = start + memTable[i].mtLength;
            for (p = (PolyWord*)start; p < (PolyWord*)end; )
            {
                p++;
                PolyObject *obj = (PolyObject*)p;
                POLYUNSIGNED length = obj->Length();
                if (length != 0 && obj->IsCodeObject())
                    machineDependent->ScanConstantsWithinCode(obj, this);
                relocateObject(obj);
                p += length;
            }
        }
        sections[i].nreloc = relocationCount;
    }

    // Additional relocations for the descriptors.
    sections[memTableEntries].reloff = ftell(exportFile);
    relocationCount = 0;

    // Address of "memTable" within "exports". We can't use createRelocation because
    // the position of the relocation is not in either the mutable or the immutable area.
    createStructsRelocation(memTableEntries, offsetof(exportDescription, memTable));

    // Address of "rootFunction" within "exports"
    unsigned rootAddrArea = findArea(rootFunction);
    POLYUNSIGNED rootOffset = (char*)rootFunction - (char*)memTable[rootAddrArea].mtAddr;
    adjustOffset(rootAddrArea, rootOffset);
    createStructsRelocation(rootAddrArea, offsetof(exportDescription, rootFunction));

    // Addresses of the areas within memtable.
    for (i = 0; i < memTableEntries; i++)
    {
        createStructsRelocation(i,
            sizeof(exportDescription) + i * sizeof(memoryTableEntry) + offsetof(memoryTableEntry, mtAddr));
    }
    sections[memTableEntries].nreloc = relocationCount;

    // The symbol name table
    symTab.stroff = ftell(exportFile);
    fwrite(stringTable.strings, stringTable.stringSize, 1, exportFile);
    symTab.strsize = stringTable.stringSize;
    alignFile(4);

    exportDescription exports;
    memset(&exports, 0, sizeof(exports));
    exports.structLength = sizeof(exportDescription);
    exports.memTableSize = sizeof(memoryTableEntry);
    exports.memTableEntries = memTableEntries;
    exports.ioIndex = 0; // The io entry is the first in the memory table
    exports.memTable = (memoryTableEntry *)sizeof(exportDescription); // It follows immediately after this.
    // Set the value to be the offset relative to the base of the area.  We have set a relocation
    // already which will add the base of the area.
    exports.rootFunction = (void*)rootOffset;
    exports.timeStamp = time(NULL);
    exports.ioSpacing = ioSpacing;
    exports.architecture = machineDependent->MachineArchitecture();
    exports.rtsVersion = POLY_version_number;

    sections[memTableEntries].offset = ftell(exportFile);
    fwrite(&exports, sizeof(exports), 1, exportFile);
    POLYUNSIGNED addrOffset = sizeof(exports)+sizeof(memoryTableEntry)*memTableEntries;
    for (i = 0; i < memTableEntries; i++)
    {
        void *save = memTable[i].mtAddr;
        memTable[i].mtAddr = (void*)addrOffset; // Set this to the relative address.
        addrOffset += memTable[i].mtLength;
        fwrite(&memTable[i], sizeof(memoryTableEntry), 1, exportFile);
        memTable[i].mtAddr = save;
    }

    // Now the binary data.
    for (i = 0; i < memTableEntries; i++)
    {
        alignFile(4);
        sections[i].offset = ftell(exportFile);
        fwrite(memTable[i].mtAddr, 1, memTable[i].mtLength, exportFile);
    }
    // Rewind to rewrite the headers with the actual offsets.
    rewind(exportFile);
    fwrite(&fhdr, sizeof(fhdr), 1, exportFile); // File header
    fwrite(&sHdr, sizeof(sHdr), 1, exportFile); // Segment header
    fwrite(sections, sectionSize * (memTableEntries+1), 1, exportFile); // Section headers
    fwrite(&symTab, sizeof(symTab), 1, exportFile); // Symbol table header
    fclose(exportFile); exportFile = NULL;

    delete[](sections);
}
Exemplo n.º 2
0
Handle poly_dispatch_c(TaskData *taskData, Handle args, Handle code)
{
    unsigned c = get_C_unsigned(taskData, DEREFWORDHANDLE(code));
    switch (c)
    {
    case 1:
        return exportNative(taskData, args); // Export
    case 2:
        raise_syscall(taskData, "C Export has been withdrawn", 0);
        return 0;
    case 3:
        return exportPortable(taskData, args); // Export as portable format

    case 9: // Return the GIT version if appropriate
        {
             return SAVE(C_string_to_Poly(taskData, GitVersion));
        }

    case 10: // Return the RTS version string.
        {
            const char *version;
            switch (machineDependent->MachineArchitecture())
            {
            case MA_Interpreted:    version = "Portable-" TextVersion; break;
            case MA_I386:           version = "I386-" TextVersion; break;
            case MA_X86_64:         version = "X86_64-" TextVersion; break;
            default:                version = "Unknown-" TextVersion; break;
            }
            return SAVE(C_string_to_Poly(taskData, version));
        }

    case 11: // Return the RTS copyright string
        return SAVE(C_string_to_Poly(taskData, poly_runtime_system_copyright));

    case 12: // Return the architecture
        {
            const char *arch;
            switch (machineDependent->MachineArchitecture())
            {
            case MA_Interpreted:    arch = "Interpreted"; break;
            case MA_I386:           arch = "I386"; break;
            case MA_X86_64:         arch = "X86_64"; break;
            default:                arch = "Unknown"; break;
            }
            return SAVE(C_string_to_Poly(taskData, arch));
        }

    case 13: // Share common immutable data.
        {
            ShareData(taskData, args);
            return SAVE(TAGGED(0));
        }

        // ObjSize and ShowSize have their own IO vector entries but really they don't
        // need them.  Include them here and add ObjProfile.
    case 14:
        return ObjSize(taskData, args);

    case 15:
        return ShowSize(taskData, args);

    case 16:
        return ObjProfile(taskData, args);

    /* 17 and 18 are no longer used. */

    case 19: // Return the RTS argument help string.
        return SAVE(C_string_to_Poly(taskData, RTSArgHelp()));

    case 20: // Write a saved state file.
        return SaveState(taskData, args);

    case 21: // Load a saved state file and any ancestors.
        return LoadState(taskData, false, args);

    case 22: // Show the hierarchy.
        return ShowHierarchy(taskData);

    case 23: // Change the name of the immediate parent stored in a child
        return RenameParent(taskData, args);

    case 24: // Return the name of the immediate parent stored in a child
        return ShowParent(taskData, args);

    case 25: // Old statistics - now removed
    case 26:
        raise_exception_string(taskData, EXC_Fail, "No statistics available");

    case 27: // Get number of user statistics available
        return Make_arbitrary_precision(taskData, N_PS_USER);

    case 28: // Set an entry in the user stats table.
        {
            unsigned index = get_C_unsigned(taskData, DEREFHANDLE(args)->Get(0));
            if (index >= N_PS_USER)
                raise_exception0(taskData, EXC_subscript);
            POLYSIGNED value = getPolySigned(taskData, DEREFHANDLE(args)->Get(1));
            globalStats.setUserCounter(index, value);
            Make_arbitrary_precision(taskData, 0);
        }

    case 29: // Get local statistics.
        return globalStats.getLocalStatistics(taskData);

    case 30: // Get remote statistics.  The argument is the process ID to get the statistics.
        return globalStats.getRemoteStatistics(taskData, getPolyUnsigned(taskData, DEREFHANDLE(args)));

    case 31: // Store a module
        return StoreModule(taskData, args);

    case 32: // Load a module
        return LoadModule(taskData, args);

    case 33: // Load hierarchy.  This provides a complete list of children and parents.
        return LoadState(taskData, true, args);

    case 34: // Return the system directory for modules.  This is configured differently
        // in Unix and in Windows.
#if (defined(MODULEDIR))
    return SAVE(C_string_to_Poly(taskData, Xstr(MODULEDIR)));
#elif (defined(_WIN32) && ! defined(__CYGWIN__))
        {
            // This registry key is configured when Poly/ML is installed using the installer.
            // It gives the path to the Poly/ML installation directory.  We return the
            // Modules subdirectory.
            HKEY hk;
            if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                    _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\PolyML.exe"), 0,
                    KEY_QUERY_VALUE, &hk) == ERROR_SUCCESS)
            {
                DWORD valSize;
                if (RegQueryValueEx(hk, _T("Path"), 0, NULL, NULL, &valSize) == ERROR_SUCCESS)
                {
#define MODULEDIR _T("Modules")
                    TempString buff((TCHAR*)malloc(valSize + (_tcslen(MODULEDIR) + 1)*sizeof(TCHAR)));
                    DWORD dwType;
                    if (RegQueryValueEx(hk, _T("Path"), 0, &dwType, (LPBYTE)(LPTSTR)buff, &valSize) == ERROR_SUCCESS)
                    {
                        RegCloseKey(hk);
                        // The registry entry should end with a backslash.
                        _tcscat(buff, MODULEDIR);
                        return SAVE(C_string_to_Poly(taskData, buff));
                    }
                }
                RegCloseKey(hk);
            }
            return SAVE(C_string_to_Poly(taskData, ""));
        }
#else
        return SAVE(C_string_to_Poly(taskData, ""));
#endif

    case 50: // GCD
        return gcd_arbitrary(taskData, SAVE(DEREFHANDLE(args)->Get(0)), SAVE(DEREFHANDLE(args)->Get(1)));
    case 51: // LCM
        return lcm_arbitrary(taskData, SAVE(DEREFHANDLE(args)->Get(0)), SAVE(DEREFHANDLE(args)->Get(1)));

        // These next ones were originally in process_env and have now been moved here,
    case 100: /* Return the maximum word segment size. */
            return taskData->saveVec.push(TAGGED(MAX_OBJECT_SIZE));
    case 101: /* Return the maximum string size (in bytes).
                 It is the maximum number of bytes in a segment
                 less one word for the length field. */
            return taskData->saveVec.push(TAGGED((MAX_OBJECT_SIZE)*sizeof(PolyWord) - sizeof(PolyWord)));
    case 102: /* Test whether the supplied address is in the io area.
                 This was previously done by having get_flags return
                 256 but this was changed so that get_flags simply
                 returns the top byte of the length word. */
        {
            PolyWord *pt = (PolyWord*)DEREFWORDHANDLE(args);
            if (gMem.IsIOPointer(pt))
                return Make_arbitrary_precision(taskData, 1);
            else return Make_arbitrary_precision(taskData, 0);
        }
    case 103: /* Return the register mask for the given function.
                 This is used by the code-generator to find out
                 which registers are modified by the function and
                 so need to be saved if they are used by the caller. */
        {
            PolyObject *pt = DEREFWORDHANDLE(args);
            if (gMem.IsIOPointer(pt))
            {
                /* IO area.  We need to get this from the vector. */
                int i;
                for (i=0; i < POLY_SYS_vecsize; i++)
                {
                    if (pt == (PolyObject*)IoEntry(i))
                    {
                        int regMask = taskData->GetIOFunctionRegisterMask(i);
                        POLYUNSIGNED props = rtsProperties(taskData, i);
                        return taskData->saveVec.push(TAGGED(regMask | props));
                    }
                }
                raise_exception_string(taskData, EXC_Fail, "Io pointer not found");
            }
            else
            {
                /* We may have a pointer to the code or a pointer to
                   a closure.  If it's a closure we have to find the
                   code. */
                if (! pt->IsCodeObject() && ! pt->IsByteObject())
                    pt = pt->Get(0).AsObjPtr();

                /* Should now be a code object. */
                if (pt->IsCodeObject())
                {
                    /* Compiled code.  This is the second constant in the
                       constant area. */
                    PolyWord *codePt = pt->ConstPtrForCode();
                    PolyWord mask = codePt[1];
                    // A real mask will be an integer.
                    if (IS_INT(mask)) return SAVE(mask);
                    else raise_exception_string(taskData, EXC_Fail, "Invalid mask");
                }
                else raise_exception_string(taskData, EXC_Fail, "Not a code pointer");
            }
        }

    case 104: return Make_arbitrary_precision(taskData, POLY_version_number);

    case 105: /* Get the name of the function. */
        {
            PolyObject *pt = DEREFWORDHANDLE(args);
            if (gMem.IsIOPointer(pt))
            {
                /* IO area. */
                int i;
                for (i=0; i < POLY_SYS_vecsize; i++)
                {
                    if (pt == (PolyObject*)IoEntry(i))
                    {
                        char buff[8];
                        sprintf(buff, "RTS%d", i);
                        return SAVE(C_string_to_Poly(taskData, buff));
                    }
                }
                raise_syscall(taskData, "Io pointer not found", 0);
            }
            else if (pt->IsCodeObject()) /* Should now be a code object. */ 
            {
                /* Compiled code.  This is the first constant in the constant area. */
                PolyWord *codePt = pt->ConstPtrForCode();
                PolyWord name = codePt[0];
                /* May be zero indicating an anonymous segment - return null string. */
                if (name == PolyWord::FromUnsigned(0))
                    return SAVE(C_string_to_Poly(taskData, ""));
                else return SAVE(name);
            }
            else raise_syscall(taskData, "Not a code pointer", 0);
        }

    default:
        {
            char msg[100];
            sprintf(msg, "Unknown poly-specific function: %d", c);
            raise_exception_string(taskData, EXC_Fail, msg);
            return 0;
        }
    }
}