[ELF] Allow target to adjust a symbol's value for using in a dynamic tag
authorSimon Atanasyan <simon@atanasyan.com>
Wed, 10 Dec 2014 20:09:12 +0000 (20:09 +0000)
committerSimon Atanasyan <simon@atanasyan.com>
Wed, 10 Dec 2014 20:09:12 +0000 (20:09 +0000)
Some targets like microMIPS and ARM Thumb use the last bit of a symbol's
value to mark 'compressed' code. This patch adds new virtual function
`DynamicTable::getAtomVirtualAddress` which allows to adjust a symbol's
value before using it in a dynamic table tags like DT_INIT / DT_FINI.

llvm-svn: 223963

lld/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h
lld/lib/ReaderWriter/ELF/SectionChunks.h
lld/test/elf/Mips/initfini-micro.test [new file with mode: 0644]

index 9a3832a..f618622 100644 (file)
@@ -91,6 +91,16 @@ public:
 
   int64_t getGotPltTag() override { return DT_MIPS_PLTGOT; }
 
+protected:
+  /// \brief Adjust the symbol's value for microMIPS code.
+  uint64_t getAtomVirtualAddress(const AtomLayout *al) const override {
+    if (const auto *da = dyn_cast<DefinedAtom>(al->_atom))
+      if (da->codeModel() == DefinedAtom::codeMipsMicro ||
+          da->codeModel() == DefinedAtom::codeMipsMicroPIC)
+        return al->_virtualAddr + 1;
+    return al->_virtualAddr;
+  }
+
 private:
   std::size_t _dt_symtabno;
   std::size_t _dt_localgot;
index 23bf012..22c2783 100644 (file)
@@ -1188,9 +1188,9 @@ public:
       _entries[_dt_fini_arraysz].d_un.d_val = finiArray->memSize();
     }
     if (const auto *al = getInitAtomLayout())
-      _entries[_dt_init].d_un.d_val = al->_virtualAddr;
+      _entries[_dt_init].d_un.d_val = getAtomVirtualAddress(al);
     if (const auto *al = getFiniAtomLayout())
-      _entries[_dt_fini].d_un.d_val = al->_virtualAddr;
+      _entries[_dt_fini].d_un.d_val = getAtomVirtualAddress(al);
     if (_layout.hasDynamicRelocationTable()) {
       auto relaTbl = _layout.getDynamicRelocationTable();
       _entries[_dt_rela].d_un.d_val = relaTbl->virtualAddr();
@@ -1209,6 +1209,14 @@ public:
 protected:
   EntriesT _entries;
 
+  /// \brief Return a virtual address (maybe adjusted) for the atom layout
+  /// Some targets like microMIPS and ARM Thumb use the last bit
+  /// of a symbol's value to mark 'compressed' code. This function allows
+  /// to adjust a virtal address before using it in the dynamic table tag.
+  virtual uint64_t getAtomVirtualAddress(const AtomLayout *al) const {
+    return al->_virtualAddr;
+  }
+
 private:
   std::size_t _dt_hash;
   std::size_t _dt_strtab;
diff --git a/lld/test/elf/Mips/initfini-micro.test b/lld/test/elf/Mips/initfini-micro.test
new file mode 100644 (file)
index 0000000..ba30e89
--- /dev/null
@@ -0,0 +1,45 @@
+# Check that if _init/_fini symbols are microMIPS encoded, DT_INIT/DT_FINI tags
+# use adjusted values with set the last bit.
+
+# RUN: yaml2obj -format=elf %s > %t.o
+# RUN: lld -flavor gnu -target mipsel -shared -o %t.so %t.o
+# RUN: llvm-readobj -symbols -dynamic-table %t.so | FileCheck %s
+
+# CHECK:      Name: _init (1)
+# CHECK-NEXT: Value: 0xF5
+# CHECK:      Name: _fini (7)
+# CHECK-NEXT: Value: 0xF9
+#
+# CHECK: 0x0000000C INIT 0xF5
+# CHECK: 0x0000000D FINI 0xF9
+
+---
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_MIPS
+  Flags:           [ EF_MIPS_ABI_O32, EF_MIPS_ARCH_32R2, EF_MIPS_MICROMIPS ]
+
+Sections:
+  - Name:          .text
+    Type:          SHT_PROGBITS
+    Flags:         [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:  0x04
+    Size:          0x18
+
+Symbols:
+  Global:
+    - Name:        _init
+      Type:        STT_FUNC
+      Section:     .text
+      Value:       0x0
+      Size:        0x4
+      Other:       [ STO_MIPS_MICROMIPS ]
+    - Name:        _fini
+      Type:        STT_FUNC
+      Section:     .text
+      Value:       0x4
+      Size:        0x4
+      Other:       [ STO_MIPS_MICROMIPS ]
+...