Re: [PATCH 3/5] LoongArch: Support relocation against _GLOBAL_OFFSET_TABLE_

From: Jinyang He
Date: Wed Jul 27 2022 - 21:03:15 EST


On 07/28/2022 12:28 AM, Xi Ruoyao wrote:
With the stack-based relocations, the assembler emits three relocations
to push the PC-relative offset of a GOT entry:

R_LARCH_SOP_PUSH_PCREL _GLOBAL_OFFSET_TABLE_
R_LARCH_SOP_PUSH_GPREL foo
R_LARCH_SOP_ADD

"_GLOBAL_OFFSET_TABLE_" does not really exist in the symtab and the BFD
linker handles it with special hack. Implement a similar hack for
kernel so we will be able to really use R_LARCH_SOP_PUSH_GPREL
relocation.

Signed-off-by: Xi Ruoyao <xry111@xxxxxxxxxxx>
---
arch/loongarch/kernel/module-sections.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)

diff --git a/arch/loongarch/kernel/module-sections.c b/arch/loongarch/kernel/module-sections.c
index 509c0b86b1e9..73976addbf60 100644
--- a/arch/loongarch/kernel/module-sections.c
+++ b/arch/loongarch/kernel/module-sections.c
@@ -89,6 +89,9 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
char *secstrings, struct module *mod)
{
unsigned int i, num_plts = 0, num_gots = 0;
+ Elf_Shdr *symtab = NULL;
+ Elf_Sym *symbols;
+ char *strings;
/*
* Find the empty .plt sections.
@@ -100,6 +103,8 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
mod->arch.plt_idx.shdr = sechdrs + i;
else if (!strcmp(secstrings + sechdrs[i].sh_name, ".got"))
mod->arch.got.shdr = sechdrs + i;
+ else if (sechdrs[i].sh_type == SHT_SYMTAB)
+ symtab = sechdrs + i;
}
if (!mod->arch.plt.shdr) {
@@ -115,6 +120,22 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
return -ENOEXEC;
}
+ if (!symtab) {
+ pr_err("%s: module symbol table missing\n", mod->name);
+ return -ENOEXEC;
+ }
+
+ symbols = (void *) ehdr + symtab->sh_offset;
+ strings = (void *) ehdr + sechdrs[symtab->sh_link].sh_offset;
+
+ for (i = 0; i < symtab->sh_size / sizeof(Elf_Sym); i++)
+ if (symbols[i].st_shndx == SHN_UNDEF &&
+ strcmp(strings + symbols[i].st_name,
+ "_GLOBAL_OFFSET_TABLE_") == 0) {
+ symbols[i].st_shndx = mod->arch.got.shdr - sechdrs;
+ symbols[i].st_value = 0;
+ }
+
/* Calculate the maxinum number of entries */
for (i = 0; i < ehdr->e_shnum; i++) {
int num_rela = sechdrs[i].sh_size / sizeof(Elf_Rela);

Hi, Ruoyao,


It is possible to create a symbol when linking, which means
maybe we can add _GLOBAL_OFFSET_TABLE_ in 'module.lds.h'.
What do you think about it?


Thanks,

Jinyang