diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp index d91c9bcd0eb..352d83d0e94 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp @@ -130,91 +130,79 @@ void RuntimeDyldMachO::finalizeLoad(ObjSectionToIDMap &SectionMap) { // symbol in the target address space. void RuntimeDyldMachO::resolveRelocation(const RelocationEntry &RE, uint64_t Value) { - const SectionEntry &Section = Sections[RE.SectionID]; - return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend, - RE.IsPCRel, RE.Size); -} + DEBUG ( + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t* LocalAddress = Section.Address + RE.Offset; + uint64_t FinalAddress = Section.LoadAddress + RE.Offset; -void RuntimeDyldMachO::resolveRelocation(const SectionEntry &Section, - uint64_t Offset, uint64_t Value, - uint32_t Type, int64_t Addend, - bool isPCRel, unsigned LogSize) { - uint8_t *LocalAddress = Section.Address + Offset; - uint64_t FinalAddress = Section.LoadAddress + Offset; - unsigned MachoType = Type; - unsigned Size = 1 << LogSize; - - DEBUG(dbgs() << "resolveRelocation LocalAddress: " - << format("%p", LocalAddress) - << " FinalAddress: " << format("%p", FinalAddress) - << " Value: " << format("%p", Value) << " Addend: " << Addend - << " isPCRel: " << isPCRel << " MachoType: " << MachoType - << " Size: " << Size << "\n"); + dbgs() << "resolveRelocation Section: " << RE.SectionID + << " LocalAddress: " << format("%p", LocalAddress) + << " FinalAddress: " << format("%p", FinalAddress) + << " Value: " << format("%p", Value) + << " Addend: " << RE.Addend + << " isPCRel: " << RE.IsPCRel + << " MachoType: " << RE.RelType + << " Size: " << (1 << RE.Size) << "\n"; + ); // This just dispatches to the proper target specific routine. switch (Arch) { default: llvm_unreachable("Unsupported CPU type!"); case Triple::x86_64: - resolveX86_64Relocation(LocalAddress, FinalAddress, (uintptr_t)Value, - isPCRel, MachoType, Size, Addend); + resolveX86_64Relocation(RE, Value); break; case Triple::x86: - resolveI386Relocation(LocalAddress, FinalAddress, (uintptr_t)Value, isPCRel, - MachoType, Size, Addend); + resolveI386Relocation(RE, Value); break; case Triple::arm: // Fall through. case Triple::thumb: - resolveARMRelocation(LocalAddress, FinalAddress, (uintptr_t)Value, isPCRel, - MachoType, Size, Addend); + resolveARMRelocation(RE, Value); break; case Triple::arm64: - resolveARM64Relocation(LocalAddress, FinalAddress, (uintptr_t)Value, - isPCRel, MachoType, Size, Addend); + resolveARM64Relocation(RE, Value); break; } } -bool RuntimeDyldMachO::resolveI386Relocation(uint8_t *LocalAddress, - uint64_t FinalAddress, - uint64_t Value, bool isPCRel, - unsigned Type, unsigned Size, - int64_t Addend) { - if (isPCRel) - Value -= FinalAddress + 4; // see resolveX86_64Relocation +bool RuntimeDyldMachO::resolveI386Relocation(const RelocationEntry &RE, + uint64_t Value) { + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t* LocalAddress = Section.Address + RE.Offset; - switch (Type) { - default: - llvm_unreachable("Invalid relocation type!"); - case MachO::GENERIC_RELOC_VANILLA: { - uint8_t *p = LocalAddress; - uint64_t ValueToWrite = Value + Addend; - for (unsigned i = 0; i < Size; ++i) { - *p++ = (uint8_t)(ValueToWrite & 0xff); - ValueToWrite >>= 8; - } - return false; + if (RE.IsPCRel) { + uint64_t FinalAddress = Section.LoadAddress + RE.Offset; + Value -= FinalAddress + 4; // see MachOX86_64::resolveRelocation. } - case MachO::GENERIC_RELOC_SECTDIFF: - case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: - case MachO::GENERIC_RELOC_PB_LA_PTR: - return Error("Relocation type not implemented yet!"); + + switch (RE.RelType) { + default: + llvm_unreachable("Invalid relocation type!"); + case MachO::GENERIC_RELOC_VANILLA: + return applyRelocationValue(LocalAddress, Value + RE.Addend, + 1 << RE.Size); + case MachO::GENERIC_RELOC_SECTDIFF: + case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: + case MachO::GENERIC_RELOC_PB_LA_PTR: + return Error("Relocation type not implemented yet!"); } } -bool RuntimeDyldMachO::resolveX86_64Relocation(uint8_t *LocalAddress, - uint64_t FinalAddress, - uint64_t Value, bool isPCRel, - unsigned Type, unsigned Size, - int64_t Addend) { +bool RuntimeDyldMachO::resolveX86_64Relocation(const RelocationEntry &RE, + uint64_t Value) { + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t* LocalAddress = Section.Address + RE.Offset; + // If the relocation is PC-relative, the value to be encoded is the // pointer difference. - if (isPCRel) + if (RE.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 -= FinalAddress + 4; + uint64_t FinalAddress = Section.LoadAddress + RE.Offset; + Value -= FinalAddress + 4; // see MachOX86_64::resolveRelocation. + } - switch (Type) { + switch (RE.RelType) { default: llvm_unreachable("Invalid relocation type!"); case MachO::X86_64_RELOC_SIGNED_1: @@ -222,17 +210,8 @@ bool RuntimeDyldMachO::resolveX86_64Relocation(uint8_t *LocalAddress, case MachO::X86_64_RELOC_SIGNED_4: case MachO::X86_64_RELOC_SIGNED: case MachO::X86_64_RELOC_UNSIGNED: - case MachO::X86_64_RELOC_BRANCH: { - Value += Addend; - // 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 *)LocalAddress; - for (unsigned i = 0; i < Size; ++i) { - *p++ = (uint8_t)Value; - Value >>= 8; - } - return false; - } + case MachO::X86_64_RELOC_BRANCH: + return applyRelocationValue(LocalAddress, Value + RE.Addend, 1 << RE.Size); case MachO::X86_64_RELOC_GOT_LOAD: case MachO::X86_64_RELOC_GOT: case MachO::X86_64_RELOC_SUBTRACTOR: @@ -241,14 +220,15 @@ bool RuntimeDyldMachO::resolveX86_64Relocation(uint8_t *LocalAddress, } } -bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress, - uint64_t FinalAddress, - uint64_t Value, bool isPCRel, - unsigned Type, unsigned Size, - int64_t Addend) { +bool RuntimeDyldMachO::resolveARMRelocation(const RelocationEntry &RE, + uint64_t Value) { + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t* LocalAddress = Section.Address + RE.Offset; + // If the relocation is PC-relative, the value to be encoded is the // pointer difference. - if (isPCRel) { + if (RE.IsPCRel) { + uint64_t FinalAddress = Section.LoadAddress + RE.Offset; Value -= FinalAddress; // ARM PCRel relocations have an effective-PC offset of two instructions // (four bytes in Thumb mode, 8 bytes in ARM mode). @@ -256,19 +236,11 @@ bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress, Value -= 8; } - switch (Type) { + switch (RE.RelType) { default: llvm_unreachable("Invalid relocation type!"); - case MachO::ARM_RELOC_VANILLA: { - // 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 *)LocalAddress; - for (unsigned i = 0; i < Size; ++i) { - *p++ = (uint8_t)Value; - Value >>= 8; - } - break; - } + case MachO::ARM_RELOC_VANILLA: + return applyRelocationValue(LocalAddress, Value, 1 << RE.Size); case MachO::ARM_RELOC_BR24: { // Mask the value into the target address. We know instructions are // 32-bit aligned, so we can do it all at once. @@ -276,13 +248,16 @@ bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress, // The low two bits of the value are not encoded. Value >>= 2; // Mask the value to 24 bits. - Value &= 0xffffff; + uint64_t FinalValue = Value & 0xffffff; + // Check for overflow. + if (Value != FinalValue) + return Error("ARM BR24 relocation out of range."); // 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; + *p = (*p & ~0xffffff) | FinalValue; break; } case MachO::ARM_THUMB_RELOC_BR22: @@ -298,29 +273,23 @@ bool RuntimeDyldMachO::resolveARMRelocation(uint8_t *LocalAddress, return false; } -bool RuntimeDyldMachO::resolveARM64Relocation(uint8_t *LocalAddress, - uint64_t FinalAddress, - uint64_t Value, bool isPCRel, - unsigned Type, unsigned Size, - int64_t Addend) { +bool RuntimeDyldMachO::resolveARM64Relocation(const RelocationEntry &RE, + uint64_t Value) { + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t* LocalAddress = Section.Address + RE.Offset; + // If the relocation is PC-relative, the value to be encoded is the // pointer difference. - if (isPCRel) + if (RE.IsPCRel) { + uint64_t FinalAddress = Section.LoadAddress + RE.Offset; Value -= FinalAddress; + } - switch (Type) { + switch (RE.RelType) { default: llvm_unreachable("Invalid relocation type!"); - case MachO::ARM64_RELOC_UNSIGNED: { - // 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 *)LocalAddress; - for (unsigned i = 0; i < Size; ++i) { - *p++ = (uint8_t)Value; - Value >>= 8; - } - break; - } + case MachO::ARM64_RELOC_UNSIGNED: + return applyRelocationValue(LocalAddress, Value, 1 << RE.Size); case MachO::ARM64_RELOC_BRANCH26: { // Mask the value into the target address. We know instructions are // 32-bit aligned, so we can do it all at once. @@ -328,9 +297,12 @@ bool RuntimeDyldMachO::resolveARM64Relocation(uint8_t *LocalAddress, // The low two bits of the value are not encoded. Value >>= 2; // Mask the value to 26 bits. - Value &= 0x3ffffff; + uint64_t FinalValue = Value & 0x3ffffff; + // Check for overflow. + if (FinalValue != Value) + return Error("ARM64 BRANCH26 relocation out of range."); // Insert the value into the instruction. - *p = (*p & ~0x3ffffff) | Value; + *p = (*p & ~0x3ffffff) | FinalValue; break; } case MachO::ARM64_RELOC_SUBTRACTOR: @@ -370,7 +342,7 @@ relocation_iterator RuntimeDyldMachO::processRelocationRef( RelocationValueRef Value; SectionEntry &Section = Sections[SectionID]; - bool isExtern = MachO->getPlainRelocationExternal(RE); + bool IsExtern = MachO->getPlainRelocationExternal(RE); bool IsPCRel = MachO->getAnyRelocationPCRel(RE); unsigned Size = MachO->getAnyRelocationLength(RE); uint64_t Offset; @@ -380,7 +352,7 @@ relocation_iterator RuntimeDyldMachO::processRelocationRef( uint64_t Addend = 0; memcpy(&Addend, LocalAddress, NumBytes); - if (isExtern) { + if (IsExtern) { // Obtain the symbol name which is referenced in the relocation symbol_iterator Symbol = RelI->getSymbol(); StringRef TargetName; @@ -425,41 +397,44 @@ relocation_iterator RuntimeDyldMachO::processRelocationRef( } else { Stubs[Value] = Section.StubOffset; uint8_t *GOTEntry = Section.Address + Section.StubOffset; - RelocationEntry RE(SectionID, Section.StubOffset, - MachO::X86_64_RELOC_UNSIGNED, 0, false, 3); + RelocationEntry GOTRE(SectionID, Section.StubOffset, + MachO::X86_64_RELOC_UNSIGNED, 0, false, 3); if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); + addRelocationForSymbol(GOTRE, Value.SymbolName); else - addRelocationForSection(RE, Value.SectionID); + addRelocationForSection(GOTRE, Value.SectionID); Section.StubOffset += 8; Addr = GOTEntry; } - resolveRelocation(Section, Offset, (uint64_t)Addr, - MachO::X86_64_RELOC_UNSIGNED, Value.Addend, true, 2); + RelocationEntry TargetRE(SectionID, Offset, + MachO::X86_64_RELOC_UNSIGNED, Value.Addend, true, + 2); + resolveRelocation(TargetRE, (uint64_t)Addr); } else if (Arch == Triple::arm && (RelType & 0xf) == MachO::ARM_RELOC_BR24) { // This is an ARM branch relocation, need to use a stub function. // Look up for existing stub. StubMap::const_iterator i = Stubs.find(Value); - if (i != Stubs.end()) - resolveRelocation(Section, Offset, (uint64_t)Section.Address + i->second, - RelType, 0, IsPCRel, Size); - else { + uint8_t *Addr; + if (i != Stubs.end()) { + Addr = Section.Address + i->second; + } else { // Create a new stub function. Stubs[Value] = Section.StubOffset; uint8_t *StubTargetAddr = createStubFunction(Section.Address + Section.StubOffset); - RelocationEntry RE(SectionID, StubTargetAddr - Section.Address, - MachO::GENERIC_RELOC_VANILLA, Value.Addend); + RelocationEntry StubRE(SectionID, StubTargetAddr - Section.Address, + MachO::GENERIC_RELOC_VANILLA, Value.Addend); if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); + addRelocationForSymbol(StubRE, Value.SymbolName); else - addRelocationForSection(RE, Value.SectionID); - resolveRelocation(Section, Offset, - (uint64_t)Section.Address + Section.StubOffset, RelType, - 0, IsPCRel, Size); + addRelocationForSection(StubRE, Value.SectionID); + Addr = Section.Address + Section.StubOffset; Section.StubOffset += getMaxStubSize(); } + RelocationEntry TargetRE(Value.SectionID, Offset, RelType, 0, IsPCRel, + Size); + resolveRelocation(TargetRE, (uint64_t)Addr); } else { RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, IsPCRel, Size); if (Value.SymbolName) diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h index 85d6501a264..0c799bd7bc4 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h @@ -25,22 +25,26 @@ using namespace llvm::object; namespace llvm { class RuntimeDyldMachO : public RuntimeDyldImpl { - bool resolveI386Relocation(uint8_t *LocalAddress, uint64_t FinalAddress, - uint64_t Value, bool isPCRel, unsigned Type, - unsigned Size, int64_t Addend); - bool resolveX86_64Relocation(uint8_t *LocalAddress, uint64_t FinalAddress, - uint64_t Value, bool isPCRel, unsigned Type, - unsigned Size, int64_t Addend); - bool resolveARMRelocation(uint8_t *LocalAddress, uint64_t FinalAddress, - uint64_t Value, bool isPCRel, unsigned Type, - unsigned Size, int64_t Addend); - bool resolveARM64Relocation(uint8_t *LocalAddress, uint64_t FinalAddress, - uint64_t Value, bool IsPCRel, unsigned Type, - unsigned Size, int64_t Addend); +private: - void resolveRelocation(const SectionEntry &Section, uint64_t Offset, - uint64_t Value, uint32_t Type, int64_t Addend, - bool isPCRel, unsigned Size); + /// Write the least significant 'Size' bytes in 'Value' out at the address + /// pointed to by Addr. Check for overflow. + bool applyRelocationValue(uint8_t *Addr, uint64_t Value, unsigned Size) { + for (unsigned i = 0; i < Size; ++i) { + *Addr++ = (uint8_t)Value; + Value >>= 8; + } + + if (Value) // Catch overflow + return Error("Relocation out of range."); + + return false; + } + + bool resolveI386Relocation(const RelocationEntry &RE, uint64_t Value); + bool resolveX86_64Relocation(const RelocationEntry &RE, uint64_t Value); + bool resolveARMRelocation(const RelocationEntry &RE, uint64_t Value); + bool resolveARM64Relocation(const RelocationEntry &RE, uint64_t Value); unsigned getMaxStubSize() override { if (Arch == Triple::arm || Arch == Triple::thumb)