[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
off)
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
+ }
+ 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
-#endif
+ }
}
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
this?
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:
0x4016c0
0x43a438
0x43a430
0x4084b5b0
0x40a2d5d8
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?
Edmund