+bool RuntimeDyldImpl::
+resolveRelocation(uint32_t BaseSection, macho::RelocationEntry RE,
+ SmallVectorImpl<void *> &SectionBases,
+ SmallVectorImpl<StringRef> &SymbolNames) {
+ // struct relocation_info {
+ // int32_t r_address;
+ // uint32_t r_symbolnum:24,
+ // r_pcrel:1,
+ // r_length:2,
+ // r_extern:1,
+ // r_type:4;
+ // };
+ uint32_t SymbolNum = RE.Word1 & 0xffffff; // 24-bit value
+ bool isPCRel = (RE.Word1 >> 24) & 1;
+ unsigned Log2Size = (RE.Word1 >> 25) & 3;
+ bool isExtern = (RE.Word1 >> 27) & 1;
+ unsigned Type = (RE.Word1 >> 28) & 0xf;
+ if (RE.Word0 & macho::RF_Scattered)
+ return Error("NOT YET IMPLEMENTED: scattered relocations.");
+
+ // The address requiring a relocation.
+ intptr_t Address = (intptr_t)SectionBases[BaseSection] + RE.Word0;
+
+ // Figure out the target address of the relocation. If isExtern is true,
+ // this relocation references the symbol table, otherwise it references
+ // a section in the same object, numbered from 1 through NumSections
+ // (SectionBases is [0, NumSections-1]).
+ intptr_t Value;
+ if (isExtern) {
+ StringRef Name = SymbolNames[SymbolNum];
+ if (SymbolTable.lookup(Name)) {
+ // The symbol is in our symbol table, so we can resolve it directly.
+ Value = (intptr_t)SymbolTable[Name];
+ } else {
+ return Error("NOT YET IMPLEMENTED: relocations to pre-compiled code.");
+ }
+ DEBUG(dbgs() << "Resolve relocation(" << Type << ") from '" << Name
+ << "' to " << format("0x%x", Address) << ".\n");
+ } else {
+ // For non-external relocations, the SymbolNum is actual a section number
+ // as described above.
+ Value = (intptr_t)SectionBases[SymbolNum - 1];
+ }
+
+ unsigned Size = 1 << Log2Size;
+ switch (CPUType) {
+ default: assert(0 && "Unsupported CPU type!");
+ case mach::CTM_x86_64:
+ return resolveX86_64Relocation(Address, Value, isPCRel, Type, Size);
+ case mach::CTM_ARM:
+ return resolveARMRelocation(Address, Value, isPCRel, Type, Size);
+ }
+ llvm_unreachable("");
+}
+
+bool RuntimeDyldImpl::resolveX86_64Relocation(intptr_t Address, intptr_t Value,
+ bool isPCRel, unsigned Type,
+ unsigned Size) {
+ // If the relocation is PC-relative, the value to be encoded is the
+ // pointer difference.
+ if (isPCRel)
+ // FIXME: It seems this value needs to be adjusted by 4 for an effective PC
+ // address. Is that expected? Only for branches, perhaps?
+ Value -= Address + 4;
+
+ switch(Type) {
+ default:
+ llvm_unreachable("Invalid relocation type!");
+ case macho::RIT_X86_64_Unsigned:
+ case macho::RIT_X86_64_Branch: {
+ // Mask in the target value a byte at a time (we don't have an alignment
+ // guarantee for the target address, so this is safest).
+ uint8_t *p = (uint8_t*)Address;
+ for (unsigned i = 0; i < Size; ++i) {
+ *p++ = (uint8_t)Value;
+ Value >>= 8;
+ }
+ return false;
+ }
+ case macho::RIT_X86_64_Signed:
+ case macho::RIT_X86_64_GOTLoad:
+ case macho::RIT_X86_64_GOT:
+ case macho::RIT_X86_64_Subtractor:
+ case macho::RIT_X86_64_Signed1:
+ case macho::RIT_X86_64_Signed2:
+ case macho::RIT_X86_64_Signed4:
+ case macho::RIT_X86_64_TLV:
+ return Error("Relocation type not implemented yet!");
+ }
+ return false;
+}
+
+bool RuntimeDyldImpl::resolveARMRelocation(intptr_t Address, intptr_t Value,
+ bool isPCRel, unsigned Type,
+ unsigned Size) {
+ // If the relocation is PC-relative, the value to be encoded is the
+ // pointer difference.
+ if (isPCRel) {
+ Value -= Address;
+ // ARM PCRel relocations have an effective-PC offset of two instructions
+ // (four bytes in Thumb mode, 8 bytes in ARM mode).
+ // FIXME: For now, assume ARM mode.
+ Value -= 8;
+ }
+
+ switch(Type) {
+ default:
+ case macho::RIT_Vanilla: {
+ llvm_unreachable("Invalid relocation type!");
+ // Mask in the target value a byte at a time (we don't have an alignment
+ // guarantee for the target address, so this is safest).
+ uint8_t *p = (uint8_t*)Address;
+ for (unsigned i = 0; i < Size; ++i) {
+ *p++ = (uint8_t)Value;
+ Value >>= 8;
+ }
+ break;
+ }
+ case macho::RIT_Pair:
+ case macho::RIT_Difference:
+ case macho::RIT_ARM_LocalDifference:
+ case macho::RIT_ARM_PreboundLazyPointer:
+ case macho::RIT_ARM_Branch24Bit: {
+ // Mask the value into the target address. We know instructions are
+ // 32-bit aligned, so we can do it all at once.
+ uint32_t *p = (uint32_t*)Address;
+ // The low two bits of the value are not encoded.
+ Value >>= 2;
+ // Mask the value to 24 bits.
+ Value &= 0xffffff;
+ // FIXME: If the destination is a Thumb function (and the instruction
+ // is a non-predicated BL instruction), we need to change it to a BLX
+ // instruction instead.
+
+ // Insert the value into the instruction.
+ *p = (*p & ~0xffffff) | Value;
+ break;
+ }
+ case macho::RIT_ARM_ThumbBranch22Bit:
+ case macho::RIT_ARM_ThumbBranch32Bit:
+ case macho::RIT_ARM_Half:
+ case macho::RIT_ARM_HalfDifference:
+ return Error("Relocation type not implemented yet!");
+ }
+ return false;
+}