[lld] r220179 - [ELF] Fix functionality of merging similar strings.

Shankar Easwaran shankarke at gmail.com
Sun Oct 19 19:59:06 PDT 2014


Author: shankare
Date: Sun Oct 19 21:59:06 2014
New Revision: 220179

URL: http://llvm.org/viewvc/llvm-project?rev=220179&view=rev
Log:
[ELF] Fix functionality of merging similar strings.

For PC relative accesses, negative addends were to be ignored. The linker was
not ignoring it and would fail with an assert. This fixes the issue and is able
to get Helloworld working.

Added:
    lld/trunk/test/elf/X86_64/mergesimilarstrings.test
Modified:
    lld/trunk/lib/ReaderWriter/ELF/ELFFile.h

Modified: lld/trunk/lib/ReaderWriter/ELF/ELFFile.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ELFFile.h?rev=220179&r1=220178&r2=220179&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ELFFile.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/ELFFile.h Sun Oct 19 21:59:06 2014
@@ -52,11 +52,11 @@ template <class ELFT> class ELFFile : pu
   // A Map is used to hold the atoms that have been divided up
   // after reading the section that contains Merge String attributes
   struct MergeSectionKey {
-    MergeSectionKey(const Elf_Shdr *shdr, int32_t offset)
+    MergeSectionKey(const Elf_Shdr *shdr, int64_t offset)
         : _shdr(shdr), _offset(offset) {}
     // Data members
     const Elf_Shdr *_shdr;
-    int32_t _offset;
+    int64_t _offset;
   };
   struct MergeSectionEq {
     int64_t operator()(const MergeSectionKey &k) const {
@@ -71,12 +71,12 @@ template <class ELFT> class ELFFile : pu
   };
 
   struct MergeString {
-    MergeString(int32_t offset, StringRef str, const Elf_Shdr *shdr,
+    MergeString(int64_t offset, StringRef str, const Elf_Shdr *shdr,
                 StringRef sectionName)
         : _offset(offset), _string(str), _shdr(shdr),
           _sectionName(sectionName) {}
     // the offset of this atom
-    int32_t _offset;
+    int64_t _offset;
     // The content
     StringRef _string;
     // Section header
@@ -92,13 +92,13 @@ template <class ELFT> class ELFFile : pu
   /// \brief find a mergeAtom given a start offset
   struct FindByOffset {
     const Elf_Shdr *_shdr;
-    uint64_t _offset;
-    FindByOffset(const Elf_Shdr *shdr, uint64_t offset)
+    int64_t _offset;
+    FindByOffset(const Elf_Shdr *shdr, int64_t offset)
         : _shdr(shdr), _offset(offset) {}
     bool operator()(const ELFMergeAtom<ELFT> *a) {
-      uint64_t off = a->offset();
+      int64_t off = a->offset();
       return (_shdr->sh_name == a->section()) &&
-             ((_offset >= off) && (_offset <= off + a->size()));
+             ((_offset >= off) && (_offset <= off + (int64_t)a->size()));
     }
   };
 
@@ -180,6 +180,12 @@ protected:
   /// Reference's target with the Atom pointer it refers to.
   virtual void updateReferences();
 
+  /// \brief Update the reference if the access corresponds to a merge string
+  /// section.
+  void updateReferenceForMergeStringAccess(ELFReference<ELFT> *ref,
+                                           const Elf_Sym *symbol,
+                                           const Elf_Shdr *shdr);
+
   /// \brief Return true if the symbol is corresponding to an architecture
   /// specific section. We will let the TargetHandler handle such atoms.
   virtual bool isTargetSpecificAtom(const Elf_Shdr *shdr, const Elf_Sym *sym);
@@ -793,6 +799,35 @@ void ELFFile<ELFT>::createRelocationRefe
   }
 }
 
+template <class ELFT>
+void ELFFile<ELFT>::updateReferenceForMergeStringAccess(ELFReference<ELFT> *ref,
+                                                        const Elf_Sym *symbol,
+                                                        const Elf_Shdr *shdr) {
+  // If the target atom is mergeable strefng atom, the atom might have been
+  // merged with other atom having the same contents. Try to find the
+  // merged one if that's the case.
+  int64_t addend = ref->addend();
+  if (addend < 0)
+    addend = 0;
+
+  const MergeSectionKey ms(shdr, addend);
+  auto msec = _mergedSectionMap.find(ms);
+  if (msec != _mergedSectionMap.end()) {
+    ref->setTarget(msec->second);
+    return;
+  }
+
+  // The target atom was not merged. Mergeable atoms are not in
+  // _symbolToAtomMapping, so we cannot find it by calling findAtom(). We
+  // instead call findMergeAtom().
+  if (symbol->getType() != llvm::ELF::STT_SECTION)
+    addend = symbol->st_value + addend;
+  ELFMergeAtom<ELFT> *mergedAtom = findMergeAtom(shdr, addend);
+  ref->setOffset(addend - mergedAtom->offset());
+  ref->setAddend(0);
+  ref->setTarget(mergedAtom);
+}
+
 template <class ELFT> void ELFFile<ELFT>::updateReferences() {
   for (auto &ri : _references) {
     if (ri->kindNamespace() == lld::Reference::KindNamespace::ELF) {
@@ -805,27 +840,7 @@ template <class ELFT> void ELFFile<ELFT>
         ri->setTarget(findAtom(symbol));
         continue;
       }
-
-      // If the target atom is mergeable string atom, the atom might have been
-      // merged with other atom having the same contents. Try to find the
-      // merged one if that's the case.
-      uint64_t addend = ri->addend();
-      const MergeSectionKey ms(shdr, addend);
-      auto msec = _mergedSectionMap.find(ms);
-      if (msec != _mergedSectionMap.end()) {
-        ri->setTarget(msec->second);
-        continue;
-      }
-
-      // The target atom was not merged. Mergeable atoms are not in
-      // _symbolToAtomMapping, so we cannot find it by calling findAtom(). We
-      // instead call findMergeAtom().
-      if (symbol->getType() != llvm::ELF::STT_SECTION)
-        addend = symbol->st_value + addend;
-      ELFMergeAtom<ELFT> *mergedAtom = findMergeAtom(shdr, addend);
-      ri->setOffset(addend - mergedAtom->offset());
-      ri->setAddend(0);
-      ri->setTarget(mergedAtom);
+      updateReferenceForMergeStringAccess(ri, symbol, shdr);
     }
   }
 }

Added: lld/trunk/test/elf/X86_64/mergesimilarstrings.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/X86_64/mergesimilarstrings.test?rev=220179&view=auto
==============================================================================
--- lld/trunk/test/elf/X86_64/mergesimilarstrings.test (added)
+++ lld/trunk/test/elf/X86_64/mergesimilarstrings.test Sun Oct 19 21:59:06 2014
@@ -0,0 +1,40 @@
+# Check that relocations to section that contains strings is properly handled
+# when merging strings is enabled.
+#
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target x86_64 %t.o --noinhibit-exec -o %t1.out
+# RUN: llvm-readobj -sections %t1.out | FileCheck %s
+
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x04
+    Content:         54889e5488d3d00000000e80000000088d3d00000000e800000000b8000000005dc3
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Link:            .symtab
+    AddressAlign:    0x04
+    Info:            .text
+    Relocations:
+      - Offset:          0x07
+        Symbol:          .rodata
+        Type:            R_X86_64_PC32
+        Addend:          -4
+  - Name:            .rodata
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_MERGE, SHF_STRINGS ]
+    AddressAlign:    0x01
+    Content:         48656c6c6f20576f726c6400576f726c6400
+Symbols:
+  Global:
+    - Name:            .rodata
+      Section:         .rodata
+
+#CHECK:    Name: .rodata
+#CHECK:    Size: 18





More information about the llvm-commits mailing list