Example #1
0
void MachoExport::writeSymbol(const char *symbolName, unsigned char nType, unsigned char nSect, unsigned long offset)
{
#if (SIZEOF_VOIDP == 8)
    struct nlist_64 symbol;
#else
    struct nlist symbol;
#endif
    memset(&symbol, 0, sizeof(symbol)); // Zero unused fields
    symbol.n_un.n_strx = stringTable.makeEntry(symbolName);
    symbol.n_type = nType;
    symbol.n_sect = nSect+1; // Sections count from 1.
    symbol.n_desc = REFERENCE_FLAG_DEFINED;
    adjustOffset(nSect, offset);
    symbol.n_value = offset;
    fwrite(&symbol, sizeof(symbol), 1, exportFile);
    symbolCount++;
}
Example #2
0
void CommentableObjectViewer::renderPosts(shared_ptr<XMLPortalExporter> exporter)
{
	if(getObject() == nullptr || getObject()->allowChild(portalObjectTypePost) == false)
		return;

	// Calcola il numero totale di posts
	uint32 total_posts = getEntity()->getChildsCount(getDatabase(), portalObjectTypePost);
	if(total_posts == 0)
		return;

	// Numero di posts da visualizzare per pagina
	uint32 posts_to_show = getSkin()->getPagerItems();
	// Inizializza l'offset di estrazione
	uint32 offset = conversions::from_utf16<uint32>(getRequest()->getUrlParam(OS_URL_PARAM_OFFSET));

	// Corregge l'offset se necessario
	adjustOffset(total_posts, posts_to_show, offset);

	objects_posts_list posts;
	// Estrae le risposte nell'intervallo richiesto
	shared_ptr<EntitiesEntities> post_childs = getEntity()->getChilds(getDatabase(), portalObjectTypePost, RangeUint32(offset, posts_to_show));
	for(EntitiesEntities::iterator i = post_childs->begin(); i != post_childs->end(); ++i)
	{
		// Carica la riposta corrente
		shared_ptr<EntitiesEntity> post_entity = post_childs->get(getDatabase(), *i);
		if(post_entity != nullptr)
		{
			// Calcola la revisione corrente della risposta
			shared_ptr<ObjectsPost> current_post = objects_post_cast(post_entity->getCurrent());
			if(current_post != nullptr)
				posts.push_back(current_post);
		}
	}

	if(posts.empty() == false)
	{
		shared_ptr<XMLNode> posts_node = exporter->getNode(OS_PORTAL_OBJECT_POST_GROUPNAME);
		for(objects_posts_list::const_iterator i = posts.begin(); i != posts.end(); ++i)
		{
			shared_ptr<XMLPortalExporter> postExporter(OS_NEW XMLPortalExporter(posts_node->addChild(OS_PORTAL_OBJECT_POST_TYPENAME), exporter->getPage(), exporter->getMode()));
			renderPost(postExporter, *i);
		}
	}

	createPager(getSkin(), exporter->getRoot(), total_posts, posts_to_show, offset);
}
Example #3
0
void sdl_visualize_clusters(point *points, int numpoints, int *cluster_centersx, int *cluster_centersy, int clusters)
{
    SDL_Init(SDL_INIT_VIDEO);

    SDL_WM_SetCaption("Cluster Visualization", "SDL Test");
    screen = SDL_SetVideoMode(WINW, WINH, 0, 0);

    SDL_Rect rect = {0, 0, WINW, WINH};
    SDL_FillRect(screen, &rect, WHITE);

    draw_points(points, numpoints, cluster_centersx, cluster_centersy, clusters);	

    debug("Entering input loop...");
    SDL_Event event;
    bool exit = false;

    while (!exit)
    {
        if (SDL_PollEvent(&event)) 
        {
            switch (event.type) 
            {
                case SDL_QUIT:
                  exit = 1;
                  break;
                case SDL_KEYDOWN:
                  switch (event.key.keysym.sym) 
                  {
		                case SDLK_UP:
			                up = true;
			            break;
		                case SDLK_DOWN:
			                down = true;
			            break;
		                case SDLK_RIGHT:
			                right = true;
			            break;
		                case SDLK_LEFT:
			                left = true;
			            break;
                      case SDLK_ESCAPE:
                      case SDLK_q:
                        exit = 1;
                        break;
                  }
                  break;
                case SDL_KEYUP:
                  switch (event.key.keysym.sym) 
                  {
		                case SDLK_UP:
			                up = false;
			            break;
		                case SDLK_DOWN:
			                down = false;
			            break;
		                case SDLK_RIGHT:
			                right = false;
			            break;
		                case SDLK_LEFT:
			                left = false;
			            break;
                      case SDLK_ESCAPE:
                      case SDLK_q:
                        exit = 1;
                        break;
                  }
                  break;
            }
        }
        if(up == true)
            adjustOffset(UP);
        if(down == true)
            adjustOffset(DOWN);
        if(left == true)
            adjustOffset(LEFT);
        if(right == true)
            adjustOffset(RIGHT);
        if(up == true || down == true || left == true || right == true)
        {
            draw_points(points, numpoints, cluster_centersx, cluster_centersy, clusters);
        }
        SDL_UpdateRect(screen, 0, 0, 0, 0);
    }
    SDL_Quit();
}
Example #4
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);
}
Example #5
0
/* This is called for each constant within the code. 
   Print a relocation entry for the word and return a value that means
   that the offset is saved in original word. */
void MachoExport::ScanConstant(byte *addr, ScanRelocationKind code)
{
    PolyWord p = GetConstantValue(addr, code);

    if (IS_INT(p) || p == PolyWord::FromUnsigned(0))
        return;

    void *a = p.AsAddress();
    unsigned aArea = findArea(a);

    // Set the value at the address to the offset relative to the symbol.
    POLYUNSIGNED offset = (char*)a - (char*)memTable[aArea].mtAddr;
    adjustOffset(aArea, offset);

    switch (code)
    {
    case PROCESS_RELOC_DIRECT: // 32 bit address of target
        {
            struct relocation_info reloc;
            setRelocationAddress(addr, &reloc.r_address);
            reloc.r_symbolnum = aArea+1; // Section numbers start at 1
            reloc.r_pcrel = 0;
#if (defined(HOSTARCHITECTURE_X86_64))
            reloc.r_length = 3; // 8 bytes
            reloc.r_type = X86_64_RELOC_UNSIGNED;
#else
            reloc.r_length = 2; // 4 bytes
            reloc.r_type = GENERIC_RELOC_VANILLA;
#endif
            reloc.r_extern = 0; // r_symbolnum is a section number.  It should be 1 if we make the IO area a common.

            for (unsigned i = 0; i < sizeof(PolyWord); i++)
            {
                addr[i] = (byte)(offset & 0xff);
                offset >>= 8;
            }
            fwrite(&reloc, sizeof(reloc), 1, exportFile);
            relocationCount++;
        }
        break;
#if (defined(HOSTARCHITECTURE_X86) || defined(HOSTARCHITECTURE_X86_64))
     case PROCESS_RELOC_I386RELATIVE:         // 32 bit relative address
        {
            unsigned addrArea = findArea(addr);
            // If it's in the same area we don't need a relocation because the
            // relative offset will be unchanged.
            if (addrArea != aArea)
            {
                struct relocation_info reloc;
                setRelocationAddress(addr, &reloc.r_address);
                reloc.r_symbolnum = aArea+1; // Section numbers start at 1
                reloc.r_pcrel = 1;
                reloc.r_length = 2; // 4 bytes
#if (defined(HOSTARCHITECTURE_X86_64))
                reloc.r_type = X86_64_RELOC_SIGNED;
#else
                reloc.r_type = GENERIC_RELOC_VANILLA;
#endif
                reloc.r_extern = 0; // r_symbolnum is a section number.
                fwrite(&reloc, sizeof(reloc), 1, exportFile);
                relocationCount++;

                POLYUNSIGNED addrOffset = (char*)addr - (char*)memTable[addrArea].mtAddr;
                adjustOffset(addrArea, addrOffset);
                offset -= addrOffset + 4;

                for (unsigned i = 0; i < 4; i++)
                {
                    addr[i] = (byte)(offset & 0xff);
                    offset >>= 8;
                }
            }
        }
        break;
#endif
        default:
            ASSERT(0); // Wrong type of relocation for this architecture.
    }
}
Example #6
0
void Screen::drawGlyph(u32 x, u32 y, u8 fc, u8 bc, u16 code, bool dw)
{
	if (x >= mWidth || y >= mHeight) return;

	s32 w = (dw ? FW(2) : FW(1)), h = FH(1);
	if (x + w > mWidth) w = mWidth - x;
	if (y + h > mHeight) h = mHeight - y;

	Font::Glyph *glyph = (Font::Glyph *)Font::instance()->getGlyph(code);
	if (!glyph) {
		fillRect(x, y, w, h, bc);
		return;
	}

	s32 top = glyph->top;
	if (top < 0) top = 0;

	s32 left = glyph->left;
	if ((s32)x + left < 0) left = -x;

	s32 width = glyph->width;
	if (width > w - left) width = w - left;
	if ((s32)x + left + width > (s32)mWidth) width = mWidth - ((s32)x + left);
	if (width < 0) width = 0;

	s32 height = glyph->height;
	if (height > h - top) height = h - top;
	if (y + top + height > mHeight) height = mHeight - (y + top);
	if (height < 0) height = 0;

	if (top) fillRect(x, y, w, top, bc);
	if (left > 0) fillRect(x, y + top, left, height, bc);

	s32 right = width + left;
	if (w > right) fillRect((s32)x + right, y + top, w - right, height, bc);

	s32 bot = top + height;
	if (h > bot) fillRect(x, y + bot, w, h - bot, bc);

	x += left;
	y += top;
	if (x >= mWidth || y >= mHeight || !width || !height) return;

	u32 nwidth = width, nheight = height;
	rotateRect(x, y, nwidth, nheight);

	u8 *pixmap = glyph->pixmap;
	u32 wdiff = glyph->width - width, hdiff = glyph->height - height;

	if (wdiff) {
		if (mRotateType == Rotate180) pixmap += wdiff;
		else if (mRotateType == Rotate270) pixmap += wdiff * glyph->pitch;
	}

	if (hdiff) {
		if (mRotateType == Rotate90) pixmap += hdiff;
		else if (mRotateType == Rotate180) pixmap += hdiff * glyph->pitch;
	}

	adjustOffset(x, y);
	for (; nheight--; y++, pixmap += glyph->pitch) {
		if ((mScrollType == YWrap) && y > mOffsetMax) y -= mOffsetMax + 1;
		(this->*draw)(x, y, nwidth, fc, bc, pixmap);
	}
}
Example #7
0
/* This is called for each constant within the code. 
   Print a relocation entry for the word and return a value that means
   that the offset is saved in original word. */
void MachoExport::ScanConstant(byte *addr, ScanRelocationKind code)
{
    PolyWord p = GetConstantValue(addr, code);

    if (IS_INT(p) || p == PolyWord::FromUnsigned(0))
        return;

    void *a = p.AsAddress();
    unsigned aArea = findArea(a);

    // Set the value at the address to the offset relative to the symbol.
    POLYUNSIGNED offset = (char*)a - (char*)memTable[aArea].mtAddr;
    adjustOffset(aArea, offset);

    switch (code)
    {
    case PROCESS_RELOC_DIRECT: // 32 bit address of target
        {
            struct relocation_info reloc;
            setRelocationAddress(addr, &reloc.r_address);
            reloc.r_symbolnum = aArea+1; // Section numbers start at 1
            reloc.r_pcrel = 0;
#if (defined(HOSTARCHITECTURE_X86_64))
            reloc.r_length = 3; // 8 bytes
            reloc.r_type = X86_64_RELOC_UNSIGNED;
#else
            reloc.r_length = 2; // 4 bytes
            reloc.r_type = GENERIC_RELOC_VANILLA;
#endif
            reloc.r_extern = 0; // r_symbolnum is a section number.  It should be 1 if we make the IO area a common.

            for (unsigned i = 0; i < sizeof(PolyWord); i++)
            {
                addr[i] = (byte)(offset & 0xff);
                offset >>= 8;
            }
            fwrite(&reloc, sizeof(reloc), 1, exportFile);
            relocationCount++;
        }
        break;
#if (defined(HOSTARCHITECTURE_X86))
     case PROCESS_RELOC_I386RELATIVE:         // 32 bit relative address
        {
            unsigned addrArea = findArea(addr);
            // If it's in the same area we don't need a relocation because the
            // relative offset will be unchanged.
            if (addrArea != aArea)
            {
                struct relocation_info reloc;
                setRelocationAddress(addr, &reloc.r_address);
                reloc.r_symbolnum = aArea+1; // Section numbers start at 1
                reloc.r_pcrel = 1;
                reloc.r_length = 2; // 4 bytes
                reloc.r_type = GENERIC_RELOC_VANILLA;
                reloc.r_extern = 0; // r_symbolnum is a section number.
                fwrite(&reloc, sizeof(reloc), 1, exportFile);
                relocationCount++;

                POLYUNSIGNED addrOffset = (char*)addr - (char*)memTable[addrArea].mtAddr;
                adjustOffset(addrArea, addrOffset);
                offset -= addrOffset + 4;

                for (unsigned i = 0; i < sizeof(PolyWord); i++)
                {
                    addr[i] = (byte)(offset & 0xff);
                    offset >>= 8;
                }
            }
        }
        break;
#endif
#ifdef HOSTARCHITECTURE_PPC
    case PROCESS_RELOC_PPCDUAL16SIGNED:       // Power PC - two consecutive words
    case PROCESS_RELOC_PPCDUAL16UNSIGNED:
        {
            struct relocation_info reloc;
            setRelocationAddress(addr, &reloc.r_address);
            POLYUNSIGNED hi = offset >> 16; // N.B. No adjustment yet.
            POLYUNSIGNED lo = offset & 0xffff;
            // We use two consecutive words for our address but Mach-O requires separate
            // relocations for each.  It stores one half of the address in the instruction
            // itself and the other half is carried in a PPC_RELOC_PAIR relocation entry.
            // We need four relocations here in total.
            reloc.r_symbolnum = aArea+1; // Section numbers start at 1
            reloc.r_extern = 0; // r_symbolnum is a section number.
            reloc.r_pcrel = 0;
            reloc.r_length = 2; // 4 bytes
            reloc.r_type = code == PROCESS_RELOC_PPCDUAL16SIGNED ? PPC_RELOC_HA16 : PPC_RELOC_HI16;
            fwrite(&reloc, sizeof(reloc), 1, exportFile);
            relocationCount++;
            // Next must be a "pair" containing the low-order part of the address.
            // The high-order part is stored in the instruction.
            reloc.r_symbolnum = 0xffffff; // Not sure why 
            reloc.r_type = PPC_RELOC_PAIR;
            reloc.r_extern = 0;
            reloc.r_pcrel = 0;
            reloc.r_address = lo;
            fwrite(&reloc, sizeof(reloc), 1, exportFile);
            relocationCount++;

            // Now the low-order part.
            setRelocationAddress(addr+sizeof(PolyWord), &reloc.r_address);
            reloc.r_symbolnum = aArea+1; // Section numbers start at 1
            reloc.r_extern = 0; // r_symbolnum is a section number.
            reloc.r_pcrel = 0;
            reloc.r_length = 2; // 4 bytes
            reloc.r_type = PPC_RELOC_LO16;
            fwrite(&reloc, sizeof(reloc), 1, exportFile);
            relocationCount++;
            // Finally a "pair" containing the high-order part of the address to
            // match the low-order part in the instruction.
            reloc.r_symbolnum = 0xffffff; // Not sure why 
            reloc.r_type = PPC_RELOC_PAIR;
            reloc.r_extern = 0;
            reloc.r_pcrel = 0;
            reloc.r_address = hi; // Must NOT be adjusted for sign extension.
            fwrite(&reloc, sizeof(reloc), 1, exportFile);
            relocationCount++;
             // Adjust for sign extension and store in the instruction.
            if ((lo & 0x8000) && (code == PROCESS_RELOC_PPCDUAL16SIGNED)) hi++;
            POLYUNSIGNED *pt = (POLYUNSIGNED *)addr;
            // Store the offset into the instructions.
            pt[0] = (pt[0] & 0xffff0000) | hi;
            pt[1] = (pt[1] & 0xffff0000) | lo;
       }
        break;
#endif
        default:
            ASSERT(0); // Wrong type of relocation for this architecture.
    }
}