[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v7 09/10] LoongArch: Support new relocation types
From: |
Xiaotian Wu |
Subject: |
[PATCH v7 09/10] LoongArch: Support new relocation types |
Date: |
Thu, 4 Aug 2022 21:01:43 +0800 |
Signed-off-by: Xiaotian Wu <wuxiaotian@loongson.cn>
---
conf/Makefile.common | 3 +
configure.ac | 14 +++--
grub-core/kern/dl.c | 9 +--
grub-core/kern/loongarch64/dl.c | 71 ++++++++++++++++++++-
grub-core/kern/loongarch64/dl_helper.c | 68 ++++++++++++++++++++
include/grub/elf.h | 6 ++
include/grub/loongarch64/reloc.h | 4 ++
util/grub-mkimagexx.c | 87 +++++++++++++++++++++++++-
util/grub-module-verifier.c | 5 ++
9 files changed, 250 insertions(+), 17 deletions(-)
diff --git a/conf/Makefile.common b/conf/Makefile.common
index 2d8f1bf2e..77f20e441 100644
--- a/conf/Makefile.common
+++ b/conf/Makefile.common
@@ -17,6 +17,9 @@ endif
if COND_arm64
CFLAGS_PLATFORM += -mcmodel=large
endif
+if COND_loongarch64
+ CFLAGS_PLATFORM += -mcmodel=large
+endif
if COND_powerpc_ieee1275
CFLAGS_PLATFORM += -mcpu=powerpc
endif
diff --git a/configure.ac b/configure.ac
index 71f65a70d..c8daf5dfb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -859,14 +859,16 @@ if ( test "x$target_cpu" = xi386 || test "x$target_cpu" =
xx86_64 ); then
fi
if test "x$target_cpu" = xloongarch64; then
- AC_CACHE_CHECK([whether -Wa,-mla-global-with-abs works],
[grub_cv_cc_mla_global_with_abs], [
- CFLAGS="$TARGET_CFLAGS -Wa,-mla-global-with-abs -Werror"
+ AC_CACHE_CHECK([whether _mno_explicit_relocs works],
[grub_cv_cc_mno_explicit_relocs], [
+ CFLAGS="$TARGET_CFLAGS -mno-explicit-relocs -Werror"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
- [grub_cv_cc_mla_global_with_abs=yes],
- [grub_cv_cc_mla_global_with_abs=no])
+ [grub_cv_cc_mno_explicit_relocs=yes],
+ [grub_cv_cc_mno_explicit_relocs=no])
])
-
- if test "x$grub_cv_cc_mla_global_with_abs" = xyes; then
+ if test "x$grub_cv_cc_mno_explicit_relocs" = xyes; then
+ TARGET_CFLAGS="$TARGET_CFLAGS -mno-explicit-relocs"
+ TARGET_CCASFLAGS="$TARGET_CCASFLAGS -mno-explicit-relocs"
+ else
TARGET_CFLAGS="$TARGET_CFLAGS -Wa,-mla-global-with-abs"
TARGET_CCASFLAGS="$TARGET_CCASFLAGS -Wa,-mla-global-with-abs"
fi
diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
index 0bf40caa6..e447fd0fa 100644
--- a/grub-core/kern/dl.c
+++ b/grub-core/kern/dl.c
@@ -225,8 +225,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
unsigned i;
const Elf_Shdr *s;
grub_size_t tsize = 0, talign = 1;
-#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \
- !defined (__loongarch__)
+#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
grub_size_t tramp;
grub_size_t got;
grub_err_t err;
@@ -242,8 +241,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
talign = s->sh_addralign;
}
-#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \
- !defined (__loongarch__)
+#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
err = grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
if (err)
return err;
@@ -306,8 +304,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
mod->segment = seg;
}
}
-#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \
- !defined (__loongarch__)
+#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN);
mod->tramp = ptr;
mod->trampptr = ptr;
diff --git a/grub-core/kern/loongarch64/dl.c b/grub-core/kern/loongarch64/dl.c
index 3a6aa91cd..127f2c2e6 100644
--- a/grub-core/kern/loongarch64/dl.c
+++ b/grub-core/kern/loongarch64/dl.c
@@ -49,6 +49,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
Elf_Shdr *s, grub_dl_segment_t seg)
{
Elf_Rel *rel, *max;
+ unsigned unmatched_got_pc_page = 0;
struct grub_loongarch64_stack stack;
grub_loongarch64_stack_init (&stack);
@@ -58,7 +59,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
rel = (Elf_Rel *) ((char *) rel + s->sh_entsize))
{
Elf_Sym *sym;
- grub_uint64_t *place;
+ void *place;
grub_uint64_t sym_addr;
if (rel->r_offset >= seg->size)
@@ -72,12 +73,19 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
if (s->sh_type == SHT_RELA)
sym_addr += ((Elf_Rela *) rel)->r_addend;
- place = (grub_uint64_t *) ((grub_addr_t)seg->addr + rel->r_offset);
+ place = (void *) ((grub_addr_t)seg->addr + rel->r_offset);
switch (ELF_R_TYPE (rel->r_info))
{
case R_LARCH_64:
- *place = sym_addr;
+ {
+ grub_uint64_t *abs_place = place;
+
+ grub_dprintf ("dl", "reloc_abs64 %p => 0x%016llx, %p\n",
+ place, (unsigned long long) sym_addr, abs_place);
+
+ *abs_place += (grub_uint64_t) sym_addr;
+ }
break;
case R_LARCH_MARK_LA:
break;
@@ -85,6 +93,63 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
case R_LARCH_SOP_PUSH_PLT_PCREL:
grub_loongarch64_sop_push (&stack, sym_addr - (grub_uint64_t)place);
break;
+ case R_LARCH_B26:
+ {
+ grub_uint32_t *abs_place = place;
+ grub_ssize_t off = sym_addr - (grub_addr_t) place;
+
+ grub_loongarch64_b26 (abs_place, off);
+ }
+ break;
+ case R_LARCH_PCALA_HI20:
+ {
+ grub_uint32_t *abs_place = place;
+ grub_int32_t off = (((sym_addr + 0x800) & ~0xfffULL) -
((grub_addr_t)place & ~0xfffULL));
+
+ grub_loongarch64_xxx_hi20 (abs_place, off);
+ }
+ break;
+ case R_LARCH_PCALA_LO12:
+ {
+ grub_uint32_t *abs_place = place;
+ grub_loongarch64_xxx_lo12 (abs_place, sym_addr);
+ }
+ break;
+ case R_LARCH_GOT_PC_HI20:
+ {
+ grub_uint64_t *gp = mod->gotptr;
+ grub_int64_t gpoffset;
+ Elf_Rela *rel2;
+
+ gpoffset = (((grub_uint64_t) gp + 0x800) & ~0xfff) -
(((grub_uint64_t) place) & ~0xfff);
+
+ *gp = (grub_uint64_t) sym_addr;
+ mod->gotptr = gp + 1;
+ unmatched_got_pc_page++;
+ grub_loongarch64_xxx_hi20 (place, gpoffset);
+ for (rel2 = (Elf_Rela *) ((char *) rel + s->sh_entsize);
+ rel2 < (Elf_Rela *) max;
+ rel2 = (Elf_Rela *) ((char *) rel2 + s->sh_entsize))
+ if (ELF_R_SYM (rel2->r_info) == ELF_R_SYM (rel->r_info)
+ && ((Elf_Rela *) rel)->r_addend == rel2->r_addend
+ && ELF_R_TYPE (rel2->r_info) == R_LARCH_GOT_PC_LO12)
+ {
+ grub_uint32_t *place2;
+ place2 = (grub_uint32_t *) ((grub_addr_t) seg->addr +
rel2->r_offset);
+ grub_loongarch64_xxx_lo12 (place2, (grub_uint64_t) gp);
+ break;
+ }
+ if (rel2 >= (Elf_Rela *) max)
+ return grub_error (GRUB_ERR_BAD_MODULE,
+ "GOT_PC_HI20 without matching GOT_PC_LO12");
+ }
+ break;
+ case R_LARCH_GOT_PC_LO12:
+ if (unmatched_got_pc_page == 0)
+ return grub_error (GRUB_ERR_BAD_MODULE,
+ "GOT_PC_LO12 without matching GOT_PC_HI20");
+ unmatched_got_pc_page--;
+ break;
GRUB_LOONGARCH64_RELOCATION (&stack, place, sym_addr)
default:
{
diff --git a/grub-core/kern/loongarch64/dl_helper.c
b/grub-core/kern/loongarch64/dl_helper.c
index 627d1fff2..a5b5b8ee9 100644
--- a/grub-core/kern/loongarch64/dl_helper.c
+++ b/grub-core/kern/loongarch64/dl_helper.c
@@ -200,3 +200,71 @@ grub_loongarch64_sop_32_s_0_10_10_16_s2
(grub_loongarch64_stack_t stack,
*place =(*place) | (((a >> 2) & 0xffff) << 10);
*place =(*place) | ((a >> 18) & 0x3ff);
}
+
+void grub_loongarch64_b26 (grub_uint32_t *place, grub_int64_t offset)
+{
+ grub_uint32_t val;
+ const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0xfc000000);
+
+ grub_dprintf ("dl", " reloc_xxxx64 %p %c= 0x%llx\n",
+ place, offset > 0 ? '+' : '-',
+ offset < 0 ? (long long) -(unsigned long long) offset : offset);
+
+ val = ((offset >> 18) & 0x3ff) | (((offset >> 2) & 0xffff) << 10);
+
+ *place &= insmask;
+ *place |= grub_cpu_to_le32 (val) & ~insmask;
+}
+
+void grub_loongarch64_xxx_hi20 (grub_uint32_t *place, grub_int64_t offset)
+{
+ const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0xfe00001f);
+ grub_uint32_t val;
+
+ offset >>= 12;
+ val = ((offset & 0xfffff) << 5);
+
+ *place &= insmask;
+ *place |= grub_cpu_to_le32 (val) & ~insmask;
+}
+
+void grub_loongarch64_xxx_lo12 (grub_uint32_t *place, grub_int64_t offset)
+{
+ const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0xffc003ff);
+
+ *place &= insmask;
+ *place |= grub_cpu_to_le32 (offset << 10) & ~insmask;
+}
+
+grub_err_t
+grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
+ grub_size_t *got)
+{
+ const Elf64_Ehdr *e = ehdr;
+ const Elf64_Shdr *s;
+ unsigned i;
+
+ *tramp = 0;
+ *got = 0;
+
+ for (i = 0, s = (Elf64_Shdr *) ((char *) e + grub_le_to_cpu64 (e->e_shoff));
+ i < grub_le_to_cpu16 (e->e_shnum);
+ i++, s = (Elf64_Shdr *) ((char *) s + grub_le_to_cpu16
(e->e_shentsize)))
+ if (s->sh_type == grub_cpu_to_le32_compile_time (SHT_RELA))
+ {
+ const Elf64_Rela *rel, *max;
+
+ for (rel = (Elf64_Rela *) ((char *) e + grub_le_to_cpu64
(s->sh_offset)),
+ max = (const Elf64_Rela *) ((char *) rel + grub_le_to_cpu64
(s->sh_size));
+ rel < max; rel = (const Elf64_Rela *) ((char *) rel +
grub_le_to_cpu64 (s->sh_entsize)))
+ switch (ELF64_R_TYPE (grub_le_to_cpu64 (rel->r_info)))
+ {
+ case R_LARCH_GOT_PC_HI20:
+ case R_LARCH_GOT_PC_LO12:
+ *got += 8;
+ break;
+ }
+ }
+
+ return GRUB_ERR_NONE;
+}
diff --git a/include/grub/elf.h b/include/grub/elf.h
index 1c8d4f5d5..5c17058f3 100644
--- a/include/grub/elf.h
+++ b/include/grub/elf.h
@@ -2554,6 +2554,12 @@ typedef Elf32_Addr Elf32_Conflict;
#define R_LARCH_SOP_POP_32_S_0_5_10_16_S2 44
#define R_LARCH_SOP_POP_32_S_0_10_10_16_S2 45
+#define R_LARCH_B26 66
+#define R_LARCH_PCALA_HI20 71
+#define R_LARCH_PCALA_LO12 72
+#define R_LARCH_GOT_PC_HI20 75
+#define R_LARCH_GOT_PC_LO12 76
+
#ifdef GRUB_TARGET_WORDSIZE
#if GRUB_TARGET_WORDSIZE == 32
diff --git a/include/grub/loongarch64/reloc.h b/include/grub/loongarch64/reloc.h
index 0b7d66ddc..ece565491 100644
--- a/include/grub/loongarch64/reloc.h
+++ b/include/grub/loongarch64/reloc.h
@@ -57,6 +57,10 @@ void grub_loongarch64_sop_32_s_0_5_10_16_s2
(grub_loongarch64_stack_t stack,
void grub_loongarch64_sop_32_s_0_10_10_16_s2 (grub_loongarch64_stack_t stack,
grub_uint64_t *place);
+void grub_loongarch64_b26 (grub_uint32_t *place, grub_int64_t offset);
+void grub_loongarch64_xxx_hi20 (grub_uint32_t *place, grub_int64_t offset);
+void grub_loongarch64_xxx_lo12 (grub_uint32_t *place, grub_int64_t
offset);
+
#define GRUB_LOONGARCH64_RELOCATION(STACK, PLACE, OFFSET) \
case R_LARCH_SOP_PUSH_ABSOLUTE: \
grub_loongarch64_sop_push (STACK, OFFSET); \
diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
index 358b9ab47..ebe200d41 100644
--- a/util/grub-mkimagexx.c
+++ b/util/grub-mkimagexx.c
@@ -1128,11 +1128,20 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct
section_metadata *smd,
}
case EM_LOONGARCH:
{
+ grub_int64_t pc;
+
+ grub_uint32_t *t32 = (grub_uint32_t *) target;
sym_addr += addend;
+
+ pc = offset + target_section_addr + image_target->vaddr_offset;
+
switch (ELF_R_TYPE (info))
{
case R_LARCH_64:
- *target = grub_host_to_target64 (grub_target_to_host64
(*target) + sym_addr);
+ {
+ grub_uint64_t *t64 = (grub_uint64_t *) target;
+ *t64 = grub_host_to_target64 (grub_target_to_host64
(*t64) + sym_addr);
+ }
break;
case R_LARCH_MARK_LA:
break;
@@ -1143,6 +1152,62 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct
section_metadata *smd,
+offset
+image_target->vaddr_offset));
break;
+ case R_LARCH_B26:
+ {
+ grub_int64_t off;
+
+ off = sym_addr - target_section_addr - offset -
image_target->vaddr_offset;
+
+ grub_loongarch64_b26 (t32, off);
+ }
+ break;
+ case R_LARCH_PCALA_HI20:
+ {
+ grub_int32_t hi20;
+
+ hi20 = (((sym_addr + 0x800) & ~0xfffULL) - (pc &
~0xfffULL));
+
+ grub_loongarch64_xxx_hi20 (t32, hi20);
+ }
+ break;
+ case R_LARCH_PCALA_LO12:
+ grub_loongarch64_xxx_lo12 (t32, sym_addr);
+ break;
+ case R_LARCH_GOT_PC_HI20:
+ {
+ Elf64_Rela *rel2;
+ grub_int32_t hi20;
+ unsigned k;
+
+ grub_int64_t gpoffset = (char *) gpptr - (char *)
pe_target + image_target->vaddr_offset;
+
+ hi20 = ((gpoffset + 0x800) & ~0xfffULL) - (pc &
~0xfffULL);
+
+ *gpptr = grub_host_to_target64 (sym_addr);
+ unmatched_adr_got_page++;
+ grub_loongarch64_xxx_hi20 ((grub_uint32_t *)target,
hi20);
+ for (k = 0, rel2 = (Elf_Rela *) ((char *) r + r_size);
+ k < num_rs;
+ k++, rel2 = (Elf_Rela *) ((char *) rel2 + r_size))
+ if (ELF_R_SYM (rel2->r_info) == ELF_R_SYM (r->r_info)
+ && r->r_addend == rel2->r_addend
+ && ELF_R_TYPE (rel2->r_info) ==
R_LARCH_GOT_PC_LO12)
+ {
+ t32 = (grub_uint32_t *) SUFFIX
(get_target_address) (e, target_section,
+
grub_target_to_host (rel2->r_offset), image_target),
+ grub_loongarch64_xxx_lo12 (t32, gpoffset);
+ break;
+ }
+ if (k >= num_rs)
+ grub_util_error ("GOT_PC_HI20 without matching
GOT_PC_LO12");
+ gpptr++;
+ }
+ break;
+ case R_LARCH_GOT_PC_LO12:
+ if (unmatched_adr_got_page == 0)
+ grub_util_error ("GOT_PC_LO12 without matching
GOT_PC_HI20");
+ unmatched_adr_got_page--;
+ break;
GRUB_LOONGARCH64_RELOCATION (&stack, target, sym_addr)
default:
grub_util_error (_("relocation 0x%x is not implemented
yet"),
@@ -1736,6 +1801,11 @@ translate_relocation_pe (struct translate_context *ctx,
case R_LARCH_SOP_POP_32_S_5_20:
case R_LARCH_SOP_POP_32_S_0_5_10_16_S2:
case R_LARCH_SOP_POP_32_S_0_10_10_16_S2:
+ case R_LARCH_B26:
+ case R_LARCH_PCALA_HI20:
+ case R_LARCH_PCALA_LO12:
+ case R_LARCH_GOT_PC_HI20:
+ case R_LARCH_GOT_PC_LO12:
grub_util_info (" %s: not adding fixup: 0x%08x : 0x%08x",
__FUNCTION__,
(unsigned int) addr,
@@ -2095,7 +2165,7 @@ make_reloc_section (Elf_Ehdr *e, struct
grub_mkimage_layout *layout,
+ image_target->vaddr_offset,
2 * layout->ia64jmpnum,
image_target);
- if (image_target->elf_target == EM_IA_64 || image_target->elf_target ==
EM_AARCH64)
+ if (image_target->elf_target == EM_IA_64 || image_target->elf_target ==
EM_AARCH64 || image_target->elf_target == EM_LOONGARCH)
create_u64_fixups (&ctx,
layout->got_off
+ image_target->vaddr_offset,
@@ -2246,6 +2316,8 @@ SUFFIX (locate_sections) (Elf_Ehdr *e, const char
*kernel_path,
/* Page-aligning simplifies relocation handling. */
if (image_target->elf_target == EM_AARCH64)
layout->align = 4096;
+ if (image_target->elf_target == EM_LOONGARCH)
+ layout->align = 4096;
layout->kernel_size = 0;
@@ -2464,6 +2536,17 @@ SUFFIX (grub_mkimage_load_image) (const char
*kernel_path,
grub_arm64_dl_get_tramp_got_size (e, &tramp, &layout->got_size);
+ layout->got_off = layout->kernel_size;
+ layout->kernel_size += ALIGN_UP (layout->got_size, 16);
+ }
+ if (image_target->elf_target == EM_LOONGARCH)
+ {
+ grub_size_t tramp;
+
+ layout->kernel_size = ALIGN_UP (layout->kernel_size, 16);
+
+ grub_arch_dl_get_tramp_got_size (e, &tramp, &layout->got_size);
+
layout->got_off = layout->kernel_size;
layout->kernel_size += ALIGN_UP (layout->got_size, 16);
}
diff --git a/util/grub-module-verifier.c b/util/grub-module-verifier.c
index b510461fa..88351e7eb 100644
--- a/util/grub-module-verifier.c
+++ b/util/grub-module-verifier.c
@@ -140,6 +140,11 @@ struct grub_module_verifier_arch archs[] = {
R_LARCH_SOP_POP_32_S_5_20,
R_LARCH_SOP_POP_32_S_0_5_10_16_S2,
R_LARCH_SOP_POP_32_S_0_10_10_16_S2,
+ R_LARCH_B26,
+ R_LARCH_PCALA_HI20,
+ R_LARCH_PCALA_LO12,
+ R_LARCH_GOT_PC_HI20,
+ R_LARCH_GOT_PC_LO12,
-1
}, (int[]){
-1
--
2.35.1
- [PATCH v7 08/10] LoongArch: Add to build system, (continued)
- [PATCH v7 01/10] PE: Add LoongArch definitions, Xiaotian Wu, 2022/08/04
- [PATCH v7 03/10] LoongArch: Add setjmp implementation, Xiaotian Wu, 2022/08/04
- [PATCH v7 05/10] LoongArch: Add stubs for Linux loading commands, Xiaotian Wu, 2022/08/04
- [PATCH v7 07/10] LoongArch: Add auxiliary files, Xiaotian Wu, 2022/08/04
- [PATCH v7 09/10] LoongArch: Support new relocation types,
Xiaotian Wu <=