mirror of
https://github.com/ventoy/Ventoy.git
synced 2025-12-17 09:06:21 +00:00
loongarch: Add support for ELF psABI v1.00 relocations
This patch adds support of the stack-based LoongArch relocations throughout GRUB, including tools, dynamic linkage, and support for conversion of ELF relocations into PE ones. A stack machine is required to handle these per the spec [1] (see the R_LARCH_SOP types), of which a simple implementation is included. These relocations are produced by binutils 2.38 and 2.39, while the newer v2.00 relocs require more recent toolchain (binutils 2.40+ & gcc 13+, or LLVM 16+). GCC 13 has not been officially released as of early 2023, so support for v1.00 relocs are expected to stay relevant for a while. [1] https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html#_relocations Signed-off-by: Zhou Yang <zhouyang@loongson.cn> Signed-off-by: Xiaotian Wu <wuxiaotian@loongson.cn> Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
This commit is contained in:
@@ -225,7 +225,8 @@ 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)
|
||||
#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \
|
||||
!defined (__loongarch__)
|
||||
grub_size_t tramp;
|
||||
grub_size_t got;
|
||||
grub_err_t err;
|
||||
@@ -241,7 +242,8 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
|
||||
talign = s->sh_addralign;
|
||||
}
|
||||
|
||||
#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
|
||||
#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \
|
||||
!defined (__loongarch__)
|
||||
err = grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -304,7 +306,8 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
|
||||
mod->segment = seg;
|
||||
}
|
||||
}
|
||||
#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv)
|
||||
#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \
|
||||
!defined (__loongarch__)
|
||||
ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN);
|
||||
mod->tramp = ptr;
|
||||
mod->trampptr = ptr;
|
||||
|
||||
102
GRUB2/MOD_SRC/grub-2.04/grub-core/kern/loongarch64/dl.c
Normal file
102
GRUB2/MOD_SRC/grub-2.04/grub-core/kern/loongarch64/dl.c
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/elf.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/cpu/reloc.h>
|
||||
|
||||
/* Check if EHDR is a valid ELF header. */
|
||||
grub_err_t
|
||||
grub_arch_dl_check_header (void *ehdr)
|
||||
{
|
||||
Elf_Ehdr *e = ehdr;
|
||||
|
||||
/* Check the magic numbers. */
|
||||
if (e->e_ident[EI_CLASS] != ELFCLASS64
|
||||
|| e->e_ident[EI_DATA] != ELFDATA2LSB || e->e_machine != EM_LOONGARCH)
|
||||
return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic"));
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||
|
||||
/*
|
||||
* Unified function for both REL and RELA.
|
||||
*/
|
||||
grub_err_t
|
||||
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
|
||||
Elf_Shdr *s, grub_dl_segment_t seg)
|
||||
{
|
||||
Elf_Rel *rel, *max;
|
||||
struct grub_loongarch64_stack stack;
|
||||
grub_loongarch64_stack_init (&stack);
|
||||
|
||||
for (rel = (Elf_Rel *) ((char *) ehdr + s->sh_offset),
|
||||
max = (Elf_Rel *) ((char *) rel + s->sh_size);
|
||||
rel < max;
|
||||
rel = (Elf_Rel *) ((char *) rel + s->sh_entsize))
|
||||
{
|
||||
Elf_Sym *sym;
|
||||
grub_uint64_t *place;
|
||||
grub_uint64_t sym_addr;
|
||||
|
||||
if (rel->r_offset >= seg->size)
|
||||
return grub_error (GRUB_ERR_BAD_MODULE,
|
||||
"reloc offset is outside the segment");
|
||||
|
||||
sym = (Elf_Sym *) ((char*) mod->symtab
|
||||
+ mod->symsize * ELF_R_SYM (rel->r_info));
|
||||
|
||||
sym_addr = sym->st_value;
|
||||
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);
|
||||
|
||||
switch (ELF_R_TYPE (rel->r_info))
|
||||
{
|
||||
case R_LARCH_64:
|
||||
*place = sym_addr;
|
||||
break;
|
||||
case R_LARCH_MARK_LA:
|
||||
break;
|
||||
case R_LARCH_SOP_PUSH_PCREL:
|
||||
case R_LARCH_SOP_PUSH_PLT_PCREL:
|
||||
grub_loongarch64_sop_push (&stack, sym_addr - (grub_uint64_t)place);
|
||||
break;
|
||||
GRUB_LOONGARCH64_RELOCATION (&stack, place, sym_addr)
|
||||
default:
|
||||
{
|
||||
char rel_info[17]; /* log16(2^64) = 16, plus NUL. */
|
||||
|
||||
grub_snprintf (rel_info, sizeof (rel_info) - 1, "%" PRIxGRUB_UINT64_T,
|
||||
(grub_uint64_t) ELF_R_TYPE (rel->r_info));
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
N_("relocation 0x%s is not implemented yet"), rel_info);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
201
GRUB2/MOD_SRC/grub-2.04/grub-core/kern/loongarch64/dl_helper.c
Normal file
201
GRUB2/MOD_SRC/grub-2.04/grub-core/kern/loongarch64/dl_helper.c
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/elf.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/loongarch64/reloc.h>
|
||||
|
||||
static void grub_loongarch64_stack_push (grub_loongarch64_stack_t stack, grub_uint64_t x);
|
||||
static grub_uint64_t grub_loongarch64_stack_pop (grub_loongarch64_stack_t stack);
|
||||
|
||||
void
|
||||
grub_loongarch64_stack_init (grub_loongarch64_stack_t stack)
|
||||
{
|
||||
stack->top = -1;
|
||||
stack->count = LOONGARCH64_STACK_MAX;
|
||||
}
|
||||
|
||||
static void
|
||||
grub_loongarch64_stack_push (grub_loongarch64_stack_t stack, grub_uint64_t x)
|
||||
{
|
||||
if (stack->top == stack->count)
|
||||
return;
|
||||
stack->data[++stack->top] = x;
|
||||
}
|
||||
|
||||
static grub_uint64_t
|
||||
grub_loongarch64_stack_pop (grub_loongarch64_stack_t stack)
|
||||
{
|
||||
if (stack->top == -1)
|
||||
return -1;
|
||||
return stack->data[stack->top--];
|
||||
}
|
||||
|
||||
void
|
||||
grub_loongarch64_sop_push (grub_loongarch64_stack_t stack, grub_int64_t offset)
|
||||
{
|
||||
grub_loongarch64_stack_push (stack, offset);
|
||||
}
|
||||
|
||||
/* opr2 = pop (), opr1 = pop (), push (opr1 - opr2) */
|
||||
void
|
||||
grub_loongarch64_sop_sub (grub_loongarch64_stack_t stack)
|
||||
{
|
||||
grub_uint64_t a, b;
|
||||
b = grub_loongarch64_stack_pop (stack);
|
||||
a = grub_loongarch64_stack_pop (stack);
|
||||
grub_loongarch64_stack_push (stack, a - b);
|
||||
}
|
||||
|
||||
/* opr2 = pop (), opr1 = pop (), push (opr1 << opr2) */
|
||||
void
|
||||
grub_loongarch64_sop_sl (grub_loongarch64_stack_t stack)
|
||||
{
|
||||
grub_uint64_t a, b;
|
||||
b = grub_loongarch64_stack_pop (stack);
|
||||
a = grub_loongarch64_stack_pop (stack);
|
||||
grub_loongarch64_stack_push (stack, a << b);
|
||||
}
|
||||
|
||||
/* opr2 = pop (), opr1 = pop (), push (opr1 >> opr2) */
|
||||
void
|
||||
grub_loongarch64_sop_sr (grub_loongarch64_stack_t stack)
|
||||
{
|
||||
grub_uint64_t a, b;
|
||||
b = grub_loongarch64_stack_pop (stack);
|
||||
a = grub_loongarch64_stack_pop (stack);
|
||||
grub_loongarch64_stack_push (stack, a >> b);
|
||||
}
|
||||
|
||||
/* opr2 = pop (), opr1 = pop (), push (opr1 + opr2) */
|
||||
void
|
||||
grub_loongarch64_sop_add (grub_loongarch64_stack_t stack)
|
||||
{
|
||||
grub_uint64_t a, b;
|
||||
b = grub_loongarch64_stack_pop (stack);
|
||||
a = grub_loongarch64_stack_pop (stack);
|
||||
grub_loongarch64_stack_push (stack, a + b);
|
||||
}
|
||||
|
||||
/* opr2 = pop (), opr1 = pop (), push (opr1 & opr2) */
|
||||
void
|
||||
grub_loongarch64_sop_and (grub_loongarch64_stack_t stack)
|
||||
{
|
||||
grub_uint64_t a, b;
|
||||
b = grub_loongarch64_stack_pop (stack);
|
||||
a = grub_loongarch64_stack_pop (stack);
|
||||
grub_loongarch64_stack_push (stack, a & b);
|
||||
}
|
||||
|
||||
/* opr3 = pop (), opr2 = pop (), opr1 = pop (), push (opr1 ? opr2 : opr3) */
|
||||
void
|
||||
grub_loongarch64_sop_if_else (grub_loongarch64_stack_t stack)
|
||||
{
|
||||
grub_uint64_t a, b, c;
|
||||
c = grub_loongarch64_stack_pop (stack);
|
||||
b = grub_loongarch64_stack_pop (stack);
|
||||
a = grub_loongarch64_stack_pop (stack);
|
||||
|
||||
if (a) {
|
||||
grub_loongarch64_stack_push (stack, b);
|
||||
} else {
|
||||
grub_loongarch64_stack_push (stack, c);
|
||||
}
|
||||
}
|
||||
|
||||
/* opr1 = pop (), (*(uint32_t *) PC) [14 ... 10] = opr1 [4 ... 0] */
|
||||
void
|
||||
grub_loongarch64_sop_32_s_10_5 (grub_loongarch64_stack_t stack,
|
||||
grub_uint64_t *place)
|
||||
{
|
||||
grub_uint64_t a = grub_loongarch64_stack_pop (stack);
|
||||
*place |= ((a & 0x1f) << 10);
|
||||
}
|
||||
|
||||
/* opr1 = pop (), (*(uint32_t *) PC) [21 ... 10] = opr1 [11 ... 0] */
|
||||
void
|
||||
grub_loongarch64_sop_32_u_10_12 (grub_loongarch64_stack_t stack,
|
||||
grub_uint64_t *place)
|
||||
{
|
||||
grub_uint64_t a = grub_loongarch64_stack_pop (stack);
|
||||
*place = *place | ((a & 0xfff) << 10);
|
||||
}
|
||||
|
||||
/* opr1 = pop (), (*(uint32_t *) PC) [21 ... 10] = opr1 [11 ... 0] */
|
||||
void
|
||||
grub_loongarch64_sop_32_s_10_12 (grub_loongarch64_stack_t stack,
|
||||
grub_uint64_t *place)
|
||||
{
|
||||
grub_uint64_t a = grub_loongarch64_stack_pop (stack);
|
||||
*place = (*place) | ((a & 0xfff) << 10);
|
||||
}
|
||||
|
||||
/* opr1 = pop (), (*(uint32_t *) PC) [25 ... 10] = opr1 [15 ... 0] */
|
||||
void
|
||||
grub_loongarch64_sop_32_s_10_16 (grub_loongarch64_stack_t stack,
|
||||
grub_uint64_t *place)
|
||||
{
|
||||
grub_uint64_t a = grub_loongarch64_stack_pop (stack);
|
||||
*place = (*place) | ((a & 0xffff) << 10);
|
||||
}
|
||||
|
||||
/* opr1 = pop (), (*(uint32_t *) PC) [25 ... 10] = opr1 [17 ... 2] */
|
||||
void
|
||||
grub_loongarch64_sop_32_s_10_16_s2 (grub_loongarch64_stack_t stack,
|
||||
grub_uint64_t *place)
|
||||
{
|
||||
grub_uint64_t a = grub_loongarch64_stack_pop (stack);
|
||||
*place = (*place) | (((a >> 2) & 0xffff) << 10);
|
||||
}
|
||||
|
||||
/* opr1 = pop (), (*(uint32_t *) PC) [24 ... 5] = opr1 [19 ... 0] */
|
||||
void
|
||||
grub_loongarch64_sop_32_s_5_20 (grub_loongarch64_stack_t stack, grub_uint64_t *place)
|
||||
{
|
||||
grub_uint64_t a = grub_loongarch64_stack_pop (stack);
|
||||
*place = (*place) | ((a & 0xfffff)<<5);
|
||||
}
|
||||
|
||||
/* opr1 = pop (), (*(uint32_t *) PC) [4 ... 0] = opr1 [22 ... 18] */
|
||||
void
|
||||
grub_loongarch64_sop_32_s_0_5_10_16_s2 (grub_loongarch64_stack_t stack,
|
||||
grub_uint64_t *place)
|
||||
{
|
||||
grub_uint64_t a = grub_loongarch64_stack_pop (stack);
|
||||
|
||||
*place =(*place) | (((a >> 2) & 0xffff) << 10);
|
||||
*place =(*place) | ((a >> 18) & 0x1f);
|
||||
}
|
||||
|
||||
/*
|
||||
* opr1 = pop ()
|
||||
* (*(uint32_t *) PC) [9 ... 0] = opr1 [27 ... 18],
|
||||
* (*(uint32_t *) PC) [25 ... 10] = opr1 [17 ... 2]
|
||||
*/
|
||||
void
|
||||
grub_loongarch64_sop_32_s_0_10_10_16_s2 (grub_loongarch64_stack_t stack,
|
||||
grub_uint64_t *place)
|
||||
{
|
||||
grub_uint64_t a = grub_loongarch64_stack_pop (stack);
|
||||
*place =(*place) | (((a >> 2) & 0xffff) << 10);
|
||||
*place =(*place) | ((a >> 18) & 0x3ff);
|
||||
}
|
||||
Reference in New Issue
Block a user