[ELF] getRelocatedSection: remove the check for ET_REL object file
authorAmir Ayupov <aaupov@fb.com>
Mon, 7 Jun 2021 20:17:00 +0000 (13:17 -0700)
committerFangrui Song <i@maskray.me>
Mon, 7 Jun 2021 20:17:00 +0000 (13:17 -0700)
getRelocatedSection interface should not check that the object file is
relocatable, as executable files may have relocations preserved with
`--emit-relocs` linker flag. The relocations are useful in context of post-link
binary analysis for function reference identification. For example, BOLT relies
on relocations to perform function reordering.

Reviewed By: MaskRay, jhenderson

Differential Revision: https://reviews.llvm.org/D102296

llvm/include/llvm/Object/ELFObjectFile.h
llvm/include/llvm/Object/ObjectFile.h
llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
llvm/lib/Object/XCOFFObjectFile.cpp
llvm/unittests/Object/ELFObjectFileTest.cpp

index 97bc076..c87a09f 100644 (file)
@@ -975,9 +975,6 @@ ELFObjectFile<ELFT>::section_rel_end(DataRefImpl Sec) const {
 template <class ELFT>
 Expected<section_iterator>
 ELFObjectFile<ELFT>::getRelocatedSection(DataRefImpl Sec) const {
-  if (EF.getHeader().e_type != ELF::ET_REL)
-    return section_end();
-
   const Elf_Shdr *EShdr = getSection(Sec);
   uintX_t Type = EShdr->sh_type;
   if (Type != ELF::SHT_REL && Type != ELF::SHT_RELA)
index c3f5fd1..267fe30 100644 (file)
@@ -132,6 +132,9 @@ public:
   iterator_range<relocation_iterator> relocations() const {
     return make_range(relocation_begin(), relocation_end());
   }
+
+  /// Returns the related section if this section contains relocations. The
+  /// returned section may or may not have applied its relocations.
   Expected<section_iterator> getRelocatedSection() const;
 
   DataRefImpl getRawDataRefImpl() const;
index efdf915..4e1cafe 100644 (file)
@@ -1687,7 +1687,8 @@ public:
       // Try to obtain an already relocated version of this section.
       // Else use the unrelocated section from the object file. We'll have to
       // apply relocations ourselves later.
-      section_iterator RelocatedSection = *SecOrErr;
+      section_iterator RelocatedSection =
+          Obj.isRelocatableObject() ? *SecOrErr : Obj.section_end();
       if (!L || !L->getLoadedSectionContents(*RelocatedSection, Data)) {
         Expected<StringRef> E = Section.getContents();
         if (E)
index 8681553..6e54e4a 100644 (file)
@@ -440,7 +440,7 @@ SubtargetFeatures XCOFFObjectFile::getFeatures() const {
 
 bool XCOFFObjectFile::isRelocatableObject() const {
   if (is64Bit())
-    report_fatal_error("64-bit support not implemented yet");
+    return !(fileHeader64()->Flags & NoRelMask);
   return !(fileHeader32()->Flags & NoRelMask);
 }
 
index bf59d4a..246406e 100644 (file)
@@ -590,3 +590,68 @@ Sections:
   DoCheck(OverLimitNumBlocks,
           "ULEB128 value at offset 0x8 exceeds UINT32_MAX (0x100000000)");
 }
+
+// Test for ObjectFile::getRelocatedSection: check that it returns a relocated
+// section for executable and relocatable files.
+TEST(ELFObjectFileTest, ExecutableWithRelocs) {
+  StringRef HeaderString(R"(
+--- !ELF
+FileHeader:
+  Class: ELFCLASS64
+  Data:  ELFDATA2LSB
+)");
+  StringRef ContentsString(R"(
+Sections:
+  - Name:  .text
+    Type:  SHT_PROGBITS
+    Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+  - Name:  .rela.text
+    Type:  SHT_RELA
+    Flags: [ SHF_INFO_LINK ]
+    Info:  .text
+)");
+
+  auto DoCheck = [&](StringRef YamlString) {
+    SmallString<0> Storage;
+    Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
+        toBinary<ELF64LE>(Storage, YamlString);
+    ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
+    const ELFObjectFile<ELF64LE> &Obj = *ElfOrErr;
+
+    bool FoundRela;
+
+    for (SectionRef Sec : Obj.sections()) {
+      Expected<StringRef> SecNameOrErr = Sec.getName();
+      ASSERT_THAT_EXPECTED(SecNameOrErr, Succeeded());
+      StringRef SecName = *SecNameOrErr;
+      if (SecName != ".rela.text")
+        continue;
+      FoundRela = true;
+      Expected<section_iterator> RelSecOrErr = Sec.getRelocatedSection();
+      ASSERT_THAT_EXPECTED(RelSecOrErr, Succeeded());
+      section_iterator RelSec = *RelSecOrErr;
+      ASSERT_NE(RelSec, Obj.section_end());
+      Expected<StringRef> TextSecNameOrErr = RelSec->getName();
+      ASSERT_THAT_EXPECTED(TextSecNameOrErr, Succeeded());
+      StringRef TextSecName = *TextSecNameOrErr;
+      EXPECT_EQ(TextSecName, ".text");
+    }
+    ASSERT_TRUE(FoundRela);
+  };
+
+  // Check ET_EXEC file (`ld --emit-relocs` use-case).
+  SmallString<128> ExecFileYamlString(HeaderString);
+  ExecFileYamlString += R"(
+  Type:  ET_EXEC
+)";
+  ExecFileYamlString += ContentsString;
+  DoCheck(ExecFileYamlString);
+
+  // Check ET_REL file.
+  SmallString<128> RelocatableFileYamlString(HeaderString);
+  RelocatableFileYamlString += R"(
+  Type:  ET_REL
+)";
+  RelocatableFileYamlString += ContentsString;
+  DoCheck(RelocatableFileYamlString);
+}