/* Get the index corresponding to an address. */ PolyWord MachoExport::createRelocation(PolyWord p, void *relocAddr) { void *addr = p.AsAddress(); unsigned addrArea = findArea(addr); POLYUNSIGNED offset = (char*)addr - (char*)memTable[addrArea].mtAddr; adjustOffset(addrArea, offset); // It looks as though struct relocation_info entries are only used // with GENERIC_RELOC_VANILLA types. struct relocation_info relInfo; setRelocationAddress(relocAddr, &relInfo.r_address); relInfo.r_symbolnum = addrArea+1; // Section numbers start at 1 relInfo.r_pcrel = 0; #if (SIZEOF_VOIDP == 8) relInfo.r_length = 3; // 8 bytes relInfo.r_type = X86_64_RELOC_UNSIGNED; #else relInfo.r_length = 2; // 4 bytes relInfo.r_type = GENERIC_RELOC_VANILLA; #endif relInfo.r_extern = 0; // r_symbolnum is a section number. It should be 1 if we make the IO area a common. fwrite(&relInfo, sizeof(relInfo), 1, exportFile); relocationCount++; return PolyWord::FromUnsigned(offset); }
// Create a relocation entry for an address at a given location. PolyWord SaveStateExport::createRelocation(PolyWord p, void *relocAddr) { RelocationEntry reloc; // Set the offset within the section we're scanning. setRelocationAddress(relocAddr, &reloc.relocAddress); void *addr = p.AsAddress(); unsigned addrArea = findArea(addr); reloc.targetAddress = (char*)addr - (char*)memTable[addrArea].mtAddr; reloc.targetSegment = (unsigned)memTable[addrArea].mtIndex; reloc.relKind = PROCESS_RELOC_DIRECT; fwrite(&reloc, sizeof(reloc), 1, exportFile); relocationCount++; return p; // Don't change the contents }
/* 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 SaveStateExport::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); // We don't need a relocation if this is relative to the current segment // since the relative address will already be right. if (code == PROCESS_RELOC_I386RELATIVE && aArea == findArea(addr)) return; // Set the value at the address to the offset relative to the symbol. RelocationEntry reloc; setRelocationAddress(addr, &reloc.relocAddress); reloc.targetAddress = (char*)a - (char*)memTable[aArea].mtAddr; reloc.targetSegment = (unsigned)memTable[aArea].mtIndex; reloc.relKind = code; fwrite(&reloc, sizeof(reloc), 1, exportFile); relocationCount++; }
/* 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. } }
/* 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. } }