[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Tinycc-devel] arm64 relocations

From: Edmund Grimley Evans
Subject: Re: [Tinycc-devel] arm64 relocations
Date: Sat, 28 Feb 2015 09:36:39 +0000
User-agent: Mutt/1.5.21 (2010-09-15)

Ignore the patch I sent earlier. I think this is a better start:

diff --git a/arm64-gen.c b/arm64-gen.c
index 737a7be..250573b 100644
--- a/arm64-gen.c
+++ b/arm64-gen.c
@@ -400,7 +400,7 @@ static void gen_fstore(int sz, int dst, int bas, uint64_t 
 static void gen_addr(int r, Sym *sym, unsigned long addend)
-#if 0
+  if (!(sym->type.t & VT_WEAK)) {
     // This is normally the right way to do it, I think,
     // but it does not work with "-run" when stdin or stderr is
     // used by the program: "R_AARCH64_ADR_PREL_PG_HI21 relocation failed".
@@ -408,7 +408,8 @@ static void gen_addr(int r, Sym *sym, unsigned long addend)
     o(0x90000000 | r);
     greloca(cur_text_section, sym, ind, R_AARCH64_ADD_ABS_LO12_NC, addend);
     o(0x91000000 | r | r << 5);
+  }
+  else {
     // This seems to work in all cases, unless you try to use an old buggy
     // GCC for linking, which says: "unresolvable R_AARCH64_MOVW_UABS_G0_NC
     // relocation against symbol `stderr@@GLIBC_2.17'".
@@ -420,7 +421,7 @@ static void gen_addr(int r, Sym *sym, unsigned long addend)
     o(0xf2c00000 | r); // movk x(rt),#...,lsl #32
     greloca(cur_text_section, sym, ind, R_AARCH64_MOVW_UABS_G3, addend);
     o(0xf2e00000 | r); // movk x(rt),#...,lsl #48
+  }
 ST_FUNC void load(int r, SValue *sv)

So on arm64 the address of data or a function is loaded using
R_AARCH64_ADR_PREL_PG_HI21 and R_AARCH64_ADD_ABS_LO12_NC, unless it's
weak, in which case I use R_AARCH64_MOVW_UABS_G0_NC, ...

GCC uses R_AARCH64_ABS64 for the weak symbols, but that doesn't matter
for now; both ways let you access the entire 64-bit address space. The
important thing is that the "HI21" and "LO12" relocations only give
you access within a range of 4 GiB so stuff in a dynamic library has
to be accessed via the PLT/GOT.

When TCC outputs a dynamically linked executable, it works:
bind_exe_dynsyms in tccelf.c creates PLT entries for the STT_FUNCs in
the library, and creates R_COPY relocations for the STT_OBJECTs.

Here's a confusing thing though: most of the PLT/GOT is created by
bind_exe_dynsyms, but after calling bind_exe_dynsyms, elf_output_file
also calls build_got_entries, which adds a couple more entries. Is
there a good reason why the PLT/GOT is created in two phases like

When you're using -run or trying to build a statically linked
executable, bind_exe_dynsyms is not called. But bind_exe_dynsyms is
the only place in TCC where R_COPY relocations are created. This
explains why the patch above doesn't work with -run.

If you're running under QEMU on a 32-bit machine it appears to work,
but you can still see the problem if you print the values of some
symbols using a test program like this:

include <math.h>
#include <stdio.h>
int main()
  printf("%p\n", &printf);
  printf("%p\n", &stdout);
  printf("%p\n", &stderr);
  printf("%p\n", &sin);
  printf("%p\n", &stdin);
  return 0;

If I run this with ./tcc -B. -run I get output like this:


So printf, stdout and stderr, which are used by TCC itself, go via
TCC's PLT/GOT, but sin and stdin don't. On 64-bit hardware the
addresses of those things would typically be much larger and out of
range of the R_AARCH64_ADR_PREL_PG_HI21 relocation so there would be
an error: "R_AARCH64_ADR_PREL_PG_HI21 relocation failed".

How to fix this? I think probably more code should be shared between
the TCC_OUTPUT_MEMORY and TCC_OUTPUT_EXE paths. In particular, the
stuff in bind_exe_dynsyms should probably happen in the MEMORY case,
too. But this stuff is not specific to any particular target
architecture. So who has the courage to rewrite it?


reply via email to

[Prev in Thread] Current Thread [Next in Thread]