2022-07-27 18:29:45

by Xi Ruoyao

[permalink] [raw]
Subject: [PATCH 0/5] LoongArch: Support new relocation types

The version 2.00 of LoongArch ELF ABI specification introduced new
relocation types, and the development tree of Binutils and GCC has
started to use them. If the kernel is built with the latest snapshot of
Binutils or GCC, it will fail to load the modules because of unrecognized
relocation types in modules.

Add support for GOT and new relocation types for the module loader, so
the kernel (with modules) can be built with the "normal" code model and
function properly.

Tested by building the kernel with Binutils & GCC master branch, and
running the kernel with 35 in-tree modules loaded.

Link: https://github.com/loongson/LoongArch-Documentation/pull/57
Link: https://gcc.gnu.org/r13-1834
Link: https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=f09482a

Xi Ruoyao (5):
LoongArch: Add section of GOT for kernel module
LoongArch: Support R_LARCH_SOP_PUSH_GPREL relocation type in kernel
module
LoongArch: Support relocation against _GLOBAL_OFFSET_TABLE_
LoongArch: Stop using undocumented assembler options
LoongArch: Support modules with new relocation types

arch/loongarch/Makefile | 5 +-
arch/loongarch/include/asm/elf.h | 37 ++++++++++
arch/loongarch/include/asm/module.h | 23 ++++++
arch/loongarch/include/asm/module.lds.h | 1 +
arch/loongarch/kernel/head.S | 10 +--
arch/loongarch/kernel/module-sections.c | 72 +++++++++++++++++--
arch/loongarch/kernel/module.c | 94 +++++++++++++++++++++++++
7 files changed, 229 insertions(+), 13 deletions(-)

--
2.37.0



2022-07-27 18:54:27

by Xi Ruoyao

[permalink] [raw]
Subject: [PATCH 3/5] LoongArch: Support relocation against _GLOBAL_OFFSET_TABLE_

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 <[email protected]>
---
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);
--
2.37.0


2022-07-28 01:21:54

by Jinyang He

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

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 <[email protected]>
> ---
> 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

2022-07-28 07:03:44

by Xi Ruoyao

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

On Thu, 2022-07-28 at 09:02 +0800, Jinyang He wrote:

> 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?

Hi Jinyang,

I think you are right, this patch can be replaced with the following,
which is much simpler.

-- >8 --

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

In normal relocatable ELF object files, "_GLOBAL_OFFSET_TABLE_" is
undefined in the symtab and the BFD linker generates it on final link.
Define it for kernel modules so we will be able to really use
R_LARCH_SOP_PUSH_GPREL relocation.

Note that we need to use "HIDDEN" to make it a local symbol because each
kernel module has its own GOT and the reference to it should not be
resolved to the GOT in the main kernel image.

Suggested-by: Jinyang He <[email protected]>
Signed-off-by: Xi Ruoyao <[email protected]>
---
arch/loongarch/include/asm/module.lds.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/loongarch/include/asm/module.lds.h b/arch/loongarch/include/asm/module.lds.h
index 57bbd0cedd26..42b7cca0b947 100644
--- a/arch/loongarch/include/asm/module.lds.h
+++ b/arch/loongarch/include/asm/module.lds.h
@@ -4,5 +4,5 @@ SECTIONS {
. = ALIGN(4);
.plt : { BYTE(0) }
.plt.idx : { BYTE(0) }
- .got : { BYTE(0) }
+ .got : { HIDDEN(_GLOBAL_OFFSET_TABLE_ = .); BYTE(0) }
}
--
2.37.0

2022-07-28 10:05:12

by Jinyang He

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

On 07/28/2022 02:41 PM, Xi Ruoyao wrote:

> On Thu, 2022-07-28 at 09:02 +0800, Jinyang He wrote:
>
>> 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?
> Hi Jinyang,
>
> I think you are right, this patch can be replaced with the following,
> which is much simpler.
>
> -- >8 --
>
> 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
>
> In normal relocatable ELF object files, "_GLOBAL_OFFSET_TABLE_" is
> undefined in the symtab and the BFD linker generates it on final link.
> Define it for kernel modules so we will be able to really use
> R_LARCH_SOP_PUSH_GPREL relocation.
>
> Note that we need to use "HIDDEN" to make it a local symbol because each
> kernel module has its own GOT and the reference to it should not be
> resolved to the GOT in the main kernel image.
>
> Suggested-by: Jinyang He <[email protected]>
> Signed-off-by: Xi Ruoyao <[email protected]>
> ---
> arch/loongarch/include/asm/module.lds.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/loongarch/include/asm/module.lds.h b/arch/loongarch/include/asm/module.lds.h
> index 57bbd0cedd26..42b7cca0b947 100644
> --- a/arch/loongarch/include/asm/module.lds.h
> +++ b/arch/loongarch/include/asm/module.lds.h
> @@ -4,5 +4,5 @@ SECTIONS {
> . = ALIGN(4);
> .plt : { BYTE(0) }
> .plt.idx : { BYTE(0) }
> - .got : { BYTE(0) }
> + .got : { HIDDEN(_GLOBAL_OFFSET_TABLE_ = .); BYTE(0) }
Not sure but maybe re-align is needed here.
Since '{BYTE(0)}' actually use 1byte. _GLOABL_OFFSET_TABLE_ may have
difference with really GOT table entry. Have no machine and without
test... :-(

Thanks,
Jinyang
> }

2022-07-28 11:04:43

by Xi Ruoyao

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

On Thu, 2022-07-28 at 17:14 +0800, Jinyang He wrote:
> Not sure but maybe re-align is needed here.
> Since '{BYTE(0)}' actually use 1byte. _GLOABL_OFFSET_TABLE_ may have
> difference with really GOT table entry. Have no machine and without
> test... :-(

BYTE(0) is only for preventing the linker from removing the section.
All we want from the linker is a slot for .got in the section table, and
the actual property (including size) will be filled at runtime by
module_frob_arch_sections. The first GOT entry won't be "appended"
after one byte, it is wrote into the start of .got (at runtime).

--
Xi Ruoyao <[email protected]>
School of Aerospace Science and Technology, Xidian University

2022-07-28 11:26:09

by Jinyang He

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

On 07/28/2022 06:57 PM, Xi Ruoyao wrote:

> On Thu, 2022-07-28 at 17:14 +0800, Jinyang He wrote:
>> Not sure but maybe re-align is needed here.
>> Since '{BYTE(0)}' actually use 1byte. _GLOABL_OFFSET_TABLE_ may have
>> difference with really GOT table entry. Have no machine and without
>> test... :-(
> BYTE(0) is only for preventing the linker from removing the section.
> All we want from the linker is a slot for .got in the section table, and
> the actual property (including size) will be filled at runtime by
> module_frob_arch_sections. The first GOT entry won't be "appended"
> after one byte, it is wrote into the start of .got (at runtime).
Thank you for the detail answer which solves a doubt
that bothered me for a long time. I used to define the
'sym' outside of '.sec'. It always failed without align.