[llvm-dev] Do I need to modify the AddrLoc of LLD for ARC target?

Leslie Zhai via llvm-dev llvm-dev at lists.llvm.org
Thu Sep 14 01:20:20 PDT 2017


The *debug* patch to verify the AddrLoc of LLD for ARC target:



Index: ELF/Arch/ARC.cpp
===================================================================
--- ELF/Arch/ARC.cpp    (nonexistent)
+++ ELF/Arch/ARC.cpp    (working copy)
@@ -0,0 +1,109 @@
+//===- ARC.cpp 
------------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Note that the current ARC support is very preliminary so you can't
+// link any useful program yet, though.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support::endian;
+using namespace llvm::ELF;
+using namespace lld;
+using namespace lld::elf;
+
+namespace {
+uint32_t middleEndianConvert(uint32_t Insn) {
+  return ((Insn & 0xffff0000) >> 16) | ((Insn & 0xffff) << 16);
+}
+
+uint32_t replaceDisp25w(uint32_t Insn, int Val) {
+  Insn = Insn & ~0x7fcffcf;
+  Insn |= ((Val >> 0) & 0x01ff) << 18;
+  Insn |= ((Val >> 9) & 0x03ff) << 6;
+  Insn |= ((Val >> 19) & 0x000f) << 0;
+  return Insn;
+}
+
+uint32_t replaceWord32(uint32_t Insn, int Val) {
+  Insn = Insn & ~0xffffffff;
+  Insn |= ((Val >> 0) & 0xffffffff) << 0;
+  return Insn;
+}
+
+class ARC final : public TargetInfo {
+public:
+  RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const 
InputFile &File,
+                     const uint8_t *Loc) const override;
+  void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const 
override;
+};
+} // namespace
+
+RelExpr ARC::getRelExpr(uint32_t Type, const SymbolBody &S,
+                        const InputFile &File, const uint8_t *Loc) const {
+  switch (Type) {
+  case R_ARC_S25W_PCREL:
+  case R_ARC_S25H_PCREL:
+  case R_ARC_S21W_PCREL:
+  case R_ARC_PC32:
+    return R_PC;
+  case R_ARC_32_ME:
+  case R_ARC_SDA16_LD2:
+  case R_ARC_SDA_LDST2:
+  case R_ARC_32:
+  case R_ARC_SDA32_ME:
+    return R_ABS;
+  default:
+    error(toString(&File) + ": unknown relocation type: " + 
toString(Type));
+    return R_HINT;
+  }
+}
+
+void ARC::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
+  int Rel = Val;
+  uint32_t Insn = read32le(Loc);
+  switch (Type) {
+  case R_ARC_S25W_PCREL:
+    Rel >>= 2;
+    Insn = middleEndianConvert(Insn);
+    Insn = replaceDisp25w(Insn, Rel);
+    Insn = middleEndianConvert(Insn);
+    errs() << "DEBUG: lld: R_ARC_S25W_PCREL: Insn: " << Insn << "\n";
+    write32le(Loc, Insn);
+    break;
+  case R_ARC_32_ME:
+  case R_ARC_SDA16_LD2:
+  case R_ARC_SDA_LDST2:
+  case R_ARC_32:
+    Insn = replaceWord32(Insn, Rel);
+    errs() << "DEBUG: lld: R_ARC_32: Insn: " << Insn << "\n";
+    write32le(Loc, Insn);
+    break;
+  case R_ARC_S25H_PCREL:
+  case R_ARC_SDA32_ME:
+  case R_ARC_S21W_PCREL:
+  case R_ARC_PC32:
+    break;
+  default:
+    error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type));
+  }
+}
+
+TargetInfo *elf::getARCTargetInfo() {
+  static ARC Target;
+  return &Target;
+}
Index: ELF/CMakeLists.txt
===================================================================
--- ELF/CMakeLists.txt    (revision 313230)
+++ ELF/CMakeLists.txt    (working copy)
@@ -9,6 +9,7 @@
  add_lld_library(lldELF
    Arch/AArch64.cpp
    Arch/AMDGPU.cpp
+  Arch/ARC.cpp
    Arch/ARM.cpp
    Arch/AVR.cpp
    Arch/Mips.cpp
Index: ELF/InputFiles.cpp
===================================================================
--- ELF/InputFiles.cpp    (revision 313230)
+++ ELF/InputFiles.cpp    (working copy)
@@ -796,6 +796,8 @@
    switch (T.getArch()) {
    case Triple::aarch64:
      return EM_AARCH64;
+  case Triple::arc:
+    return EM_ARC_COMPACT;
    case Triple::arm:
    case Triple::thumb:
      return EM_ARM;
Index: ELF/InputSection.cpp
===================================================================
--- ELF/InputSection.cpp    (revision 313230)
+++ ELF/InputSection.cpp    (working copy)
@@ -677,6 +677,8 @@
      if (!Sym.isTls() || Out::TlsPhdr)
        SymVA = SignExtend64<sizeof(typename ELFT::uint) * 8>(
            getRelocTargetVA(Type, Addend, AddrLoc, Sym, R_ABS));
+    errs() << "DEBUG: lld: " << toString(Type) << " SymVA: " << SymVA 
<< " A: "
+           << Addend << " P: " << AddrLoc << "\n";
      Target->relocateOne(BufLoc, Type, SymVA);
    }
  }
@@ -716,6 +718,17 @@

      uint64_t AddrLoc = getOutputSection()->Addr + Offset;
      RelExpr Expr = Rel.Expr;
+    if ((Expr == R_PC || Expr == R_GOT_PC) &&
+        (Config->EMachine == EM_ARC_COMPACT ||
+         Config->EMachine == EM_ARC_COMPACT2)) {
+      uint64_t M = 0;
+      if (Type == R_ARC_32_PCREL || Type == R_ARC_PC32 ||
+          Type == R_ARC_GOTPC32 || Type == R_ARC_GOTPC)
+        M = 4; // bitsize >= 32 ? 4 : 0
+      AddrLoc = (getOutputSection()->Addr /* output_section->vma */ +
+              cast<InputSection>(this)->OutSecOff /* output_offset */ +
+              Offset /* reloc_offset */ - M) & ~0x3;
+    }
      uint64_t TargetVA = SignExtend64(
          getRelocTargetVA(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), 
Bits);

@@ -746,6 +759,11 @@
          write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1)
        LLVM_FALLTHROUGH;
      default:
+      errs() << "DEBUG: lld: " << toString(Type) << " TargetVA: " << 
TargetVA
+             << " A: " << Rel.Addend << " P: " << AddrLoc << " VMA: "
+             << getOutputSection()->Addr << " Output Offset: "
+             << cast<InputSection>(this)->OutSecOff << " Reloc Offset: "
+             << Offset << "\n";
        Target->relocateOne(BufLoc, Type, TargetVA);
        break;
      }
Index: ELF/Target.cpp
===================================================================
--- ELF/Target.cpp    (revision 313230)
+++ ELF/Target.cpp    (working copy)
@@ -56,6 +56,9 @@
      return getAArch64TargetInfo();
    case EM_AMDGPU:
      return getAMDGPUTargetInfo();
+  case EM_ARC_COMPACT:
+  case EM_ARC_COMPACT2:
+    return getARCTargetInfo();
    case EM_ARM:
      return getARMTargetInfo();
    case EM_AVR:
Index: ELF/Target.h
===================================================================
--- ELF/Target.h    (revision 313230)
+++ ELF/Target.h    (working copy)
@@ -112,6 +112,7 @@

  TargetInfo *getAArch64TargetInfo();
  TargetInfo *getAMDGPUTargetInfo();
+TargetInfo *getARCTargetInfo();
  TargetInfo *getARMTargetInfo();
  TargetInfo *getAVRTargetInfo();
  TargetInfo *getPPC64TargetInfo();
Index: test/lit.cfg
===================================================================
--- test/lit.cfg    (revision 313230)
+++ test/lit.cfg    (working copy)
@@ -247,6 +247,8 @@
      config.available_features.add('aarch64')
  if re.search(r'AMDGPU', archs):
      config.available_features.add('amdgpu')
+if re.search(r'ARC', archs):
+    config.available_features.add('arc')
  if re.search(r'ARM', archs):
      config.available_features.add('arm')
  if re.search(r'AVR', archs):
Index: test/ELF/basic-arc.s
===================================================================
--- test/ELF/basic-arc.s    (nonexistent)
+++ test/ELF/basic-arc.s    (working copy)
@@ -0,0 +1,10 @@
+# REQUIRES: arc
+# RUN: llvm-mc -filetype=obj -triple=arc-unknown-linux -mcpu=arc600 %s 
-o %t.o
+# RUN: ld.lld %t.o -o %t.exe -Ttext=0
+# RUN: llvm-objdump -d %t.exe | FileCheck %s
+
+main:
+  bl memset
+
+# CHECK:      main:
+# CHECK-NEXT:   0: 08 06 00 00 <unknown>



I modified the AddrLoc in InputSectionBase::relocateAlloc based on the 
ARC ld's P 
https://github.com/foss-for-synopsys-dwc-arc-processors/binutils-gdb/blob/arc-2017.09/bfd/elf32-arc.c#L1178


DEBUG: arc-ld: R_ARC_S25W_PCREL relocation: 2 S: 12 A: 0 P: 4 = (vma: 6 
+ output_offset: 0 + reloc_offset: 0 - 0) & ~0x3
DEBUG: arc-ld: type: R_ARC_S25W_PCREL insn: 2058

DEBUG: lld: R_ARC_S25W_PCREL TargetVA: 4 A: 0 P: 8 VMA: 8 Output Offset: 
0 Reloc Offset: 0
DEBUG: lld: R_ARC_S25W_PCREL: Insn: 2054

What is the equivalent of *vma* in LLD? please give me some hints, 
thanks a lot!


在 2017年09月14日 14:16, Leslie Zhai 写道:
> Hi LLVM developers,
>
> basic-arc.s:
>
> main:
>   bl memset
>
> $ arc-elf32-gcc -mcpu=arc600 -o basic-arc.o -c
>
> $ arc-elf32-readelf -r basic-arc.o
>
> Relocation section '.rela.text' at offset 0xd4 contains 1 entries:
>  Offset     Info    Type            Sym.Value  Sym. Name + Addend
> 00000000  00000611 R_ARC_S25W_PCREL  00000000   memset + 0
>
> High address: 0x0
>
> $ arc-elf32-ld -o basic-arc basic-arc.o 
> -L/opt/arc-gnu/lib/gcc/arc-elf32/7.1.1/arc600 
> -L/opt/arc-gnu/lib/gcc/arc-elf32/7.1.1/../../../../arc-elf32/lib/arc600 
> -L/opt/arc-gnu/lib/gcc/arc-elf32/7.1.1 
> -L/opt/arc-gnu/lib/gcc/arc-elf32/7.1.1/../../../../arc-elf32/lib 
> --start-group -lgcc -lc -lnosys --end-group -Ttext=0
>
> DEBUG: arc-ld: R_ARC_S25W_PCREL relocation: 1 S: 4 A: 0 P: 0 = (vma: 0 
> + output_offset: 0 + reloc_offset: 0 - 0) & ~0x3
> DEBUG: arc-ld: type: R_ARC_S25W_PCREL insn: 2054
>
> $ ld.lld -o basic-arc-lld basic-arc.o $ARC_LINKER_LIB -Ttext=0
>
> DEBUG: lld: R_ARC_S25W_PCREL TargetVA: 4 A: 0 P: 0 <-- same P as arc-ld
> DEBUG: lld: R_ARC_S25W_PCREL: Insn: 2050 Rel: 1
> DEBUG: lld: R_ARC_S25W_PCREL: Insn: 2054 <-- same relocation value as 
> arc-ld
>
> But with several different high address *not* 0x0, such as 0x6:
>
> DEBUG: arc-ld: R_ARC_S25W_PCREL relocation: 2 S: 12 A: 0 P: 4 = (vma: 
> 6 + output_offset: 0 + reloc_offset: 0 - 0) & ~0x3
> DEBUG: arc-ld: type: R_ARC_S25W_PCREL insn: 2058
>
> DEBUG: lld: R_ARC_S25W_PCREL TargetVA: 4 A: 0 P: 8 <-- different P?
> DEBUG: lld: R_ARC_S25W_PCREL: Insn: 2050 Rel: 1
> DEBUG: lld: R_ARC_S25W_PCREL: Insn: 2054 <-- different relocation value
>
> How arc-ld calculates P?
>
> P = ((reloc_data.input_section->output_section ? 
> reloc_data.input_section->output_section->vma : 0) + 
> reloc_data.input_section->output_offset + (reloc_data.reloc_offset - 
> (reloc_data.bitsize >= 32 ? 4 : 0))) & ~0x3;
>
> for example, R_ARC_S25W_PCREL's bitsize < 32, P = (6 + 0 + 0 - 0) & 
> ~0x3 = 4, when vma is 6, output and reloc offset is 0.
>
> How LLD calculates P (AddrLoc)?
>
> P = getOutputSection()->Addr + getOffset(Rel.Offset);
>
> for example, the same high address 0x6, LLD's P is 8, different with 
> arc-ld? so do I need to modify the value of P for R_PC case in the 
> getRelocTargetVA? please give me some hints, thanks a lot!
>
>
> PS: arc-ld R_ARC_S25W_PCREL's FORMULA is: ( S + A ) - P ) >> 2, and it 
> needs middle endian convert, so:
>
> Insn = middleEndianConvert (insn, TRUE);
>
> Insn = replaceDisp25w(Insn, ( S + A ) - P ) >> 2);
>
> Insn = middleEndianConvert (insn, TRUE);
>
> write32le(Loc, Insn);
>

-- 
Regards,
Leslie Zhai - https://reviews.llvm.org/p/xiangzhai/





More information about the llvm-dev mailing list