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.
This series does not break the compatibility with old toolchain using
stack-based relocation types, so with the patches applied the kernel can
be be built with both old and new toolchains. But, the combination of
"new" Binutils and "old" GCC is not supported.
Tested by building the kernel with the following combinations:
- GCC 12 and Binutils 2.39
- GCC trunk and Binutils trunk
and running the builds with 35 in-tree modules loaded, and loading one
module with 20 GOT loads and a per-CPU variable (loaded addresses
verified by comparing with /proc/kallsyms).
Changes from v5 to v6:
- Restore version number.
- Rename CONFIG_CC_HAS_EXPLICIT_RELOCS to CONFIG_AS_HAS_EXPLICIT_RELOCS.
It now only checks assembler.
- No longer support "old GCC with new Binutils", so R_LARCH_ABS* is
dropped.
- "Old GCC with old Binutils" is still supported until Arnd ack.
longer support it.
- "New GCC with old Binutils" is still supported as it does not
require additional code.
- Remove "cc-option" around "-mexplicit-relocs". For unsupported
"old GCC with new Binutils" combination, forcing -mexplicit-relocs
makes assembling fail, instead of silently producing unloadable
modules.
- Move the error report for "lacking model attribute" into Makefile.
- Squash the two patches for R_LARCH_B26 and R_LARCH_PCALA* into one.
Changes from v4 to v5 ("v5" missed in the subject):
- Change subject.
- Introduce CONFIG_CC_HAS_EXPLICIT_RELOCS.
- Retain -Wa,-mla-* options for old toolchains
(!CONFIG_CC_HAS_EXPLICIT_RELOCS).
- Use __attribute__((model("extreme"))) in PER_CPU_ATTRIBUTES, to fix
a breakage with per-CPU variables defined in modules.
- Handle R_LARCH_PCALA64_{HI12,LO12} for extreme model.
- Handle R_LARCH_ABS* for "old GCC with new Binutils".
- Separate the last patch into more small patches.
- Avoid BUG_ON() for the handling of GOT.
Changes from v3 to v4:
- No code change. Reword the commit message of the 3rd patch again
based on suggestion from Huacai.
Changes from v2 to v3:
- Use `union loongarch_instruction` instead of explicit bit shifts
applying the relocation. Suggested by Youling.
- For R_LARCH_B26, move the alignment check before the range check to be
consistent with stack pop relocations. Suggested by Youling.
- Reword the commit message of the 3rd patch. Suggested by Huacai.
Changes from v1 to v2:
- Fix a stupid programming error (confusion between the number of PLT
entries and the number of GOT entries). (Bug spotted by Youling).
- Synthesize the _GLOBAL_OFFSET_TABLE_ symbol with module.lds, instead
of faking it at runtime. The 3rd patch from V1 is now merged into
the 1st patch because it would be a one-line change. (Suggested by
Jinyang).
- Keep reloc_rela_handlers[] ordered by the relocation type ID.
(Suggested by Youling).
- Remove -fplt along with -Wa,-mla-* options because it's the default.
(Suggested by Youling).
Xi Ruoyao (6):
LoongArch: Add CONFIG_AS_HAS_EXPLICIT_RELOCS
LoongArch: Adjust CFLAGS for CONFIG_AS_HAS_EXPLICIT_RELOCS
LoongArch: Use model("extreme") attribute for per-CPU variables in
module if CONFIG_AS_HAS_EXPLICIT_RELOCS
LoongArch: Define ELF relocation types added in v2.00 ABI
LoongArch: Support PC-relative relocations in modules
LoongArch: Support R_LARCH_GOT_PC* in modules
arch/loongarch/Kconfig | 3 +
arch/loongarch/Makefile | 22 +++++-
arch/loongarch/include/asm/elf.h | 37 +++++++++
arch/loongarch/include/asm/module.h | 23 ++++++
arch/loongarch/include/asm/module.lds.h | 1 +
arch/loongarch/include/asm/percpu.h | 8 ++
arch/loongarch/kernel/head.S | 10 +--
arch/loongarch/kernel/module-sections.c | 56 ++++++++++++-
arch/loongarch/kernel/module.c | 101 +++++++++++++++++++++++-
9 files changed, 250 insertions(+), 11 deletions(-)
--
2.37.0
On LoongArch, The "address" of a per-CPU variable symbol is actually an
offset from $r21. The value is nearing the loading address of main
kernel image, but far from the address of modules. We need to tell the
compiler that a PC-relative addressing with 32-bit offset is not
sufficient for local per-CPU variables.
After some discussion with GCC maintainers, we implemented this
attribute to indicate that a PC-relative addressing with 64-bit offset
should be used.
This attribute should be available in GCC 13 release. Some early GCC 13
snapshots may support -mexplicit-relocs but lack this attribute, we
simply reject them.
Signed-off-by: Xi Ruoyao <[email protected]>
Link: https://gcc.gnu.org/r13-2199
---
arch/loongarch/Makefile | 3 +++
arch/loongarch/include/asm/percpu.h | 8 ++++++++
2 files changed, 11 insertions(+)
diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
index 1563747c4fa8..593818a61741 100644
--- a/arch/loongarch/Makefile
+++ b/arch/loongarch/Makefile
@@ -53,6 +53,9 @@ LDFLAGS_vmlinux += -G0 -static -n -nostdlib
# combination of a "new" assembler and "old" compiler is not supported. Either
# upgrade the compiler or downgrade the assembler.
ifdef CONFIG_AS_HAS_EXPLICIT_RELOCS
+ifeq ($(shell echo '__has_attribute(model)' | $(CC) -E -P - 2> /dev/null), 0)
+$(error "C compiler must support model attribute if using explicit relocs")
+endif
cflags-y += -mexplicit-relocs
else
cflags-y += $(call cc-option,-mno-explicit-relocs)
diff --git a/arch/loongarch/include/asm/percpu.h b/arch/loongarch/include/asm/percpu.h
index 0bd6b0110198..dd7fcc553efa 100644
--- a/arch/loongarch/include/asm/percpu.h
+++ b/arch/loongarch/include/asm/percpu.h
@@ -8,6 +8,14 @@
#include <asm/cmpxchg.h>
#include <asm/loongarch.h>
+#if defined(MODULE) && defined(CONFIG_AS_HAS_EXPLICIT_RELOCS)
+/* The "address" (in fact, offset from $r21) of a per-CPU variable is close
+ * to the load address of main kernel image, but far from where the modules are
+ * loaded. Tell the compiler this fact.
+ */
+# define PER_CPU_ATTRIBUTES __attribute__((model("extreme")))
+#endif
+
/* Use r21 for fast access */
register unsigned long __my_cpu_offset __asm__("$r21");
--
2.37.0
Binutils >= 2.40 uses R_LARCH_B26 instead of R_LARCH_SOP_PUSH_PLT_PCREL,
and R_LARCH_PCALA* instead of R_LARCH_SOP_PUSH_PCREL.
Handle R_LARCH_B26 and R_LARCH_PCALA* in the module loader. For
R_LARCH_B26, also create a PLT entry as needed.
Signed-off-by: Xi Ruoyao <[email protected]>
---
arch/loongarch/kernel/module-sections.c | 7 ++-
arch/loongarch/kernel/module.c | 75 +++++++++++++++++++++++++
2 files changed, 81 insertions(+), 1 deletion(-)
diff --git a/arch/loongarch/kernel/module-sections.c b/arch/loongarch/kernel/module-sections.c
index 6d498288977d..c67b9cb220eb 100644
--- a/arch/loongarch/kernel/module-sections.c
+++ b/arch/loongarch/kernel/module-sections.c
@@ -56,9 +56,14 @@ static void count_max_entries(Elf_Rela *relas, int num, unsigned int *plts)
for (i = 0; i < num; i++) {
type = ELF_R_TYPE(relas[i].r_info);
- if (type == R_LARCH_SOP_PUSH_PLT_PCREL) {
+ switch (type) {
+ case R_LARCH_SOP_PUSH_PLT_PCREL:
+ case R_LARCH_B26:
if (!duplicate_rela(relas, i))
(*plts)++;
+ break;
+ default:
+ /* Do nothing. */
}
}
}
diff --git a/arch/loongarch/kernel/module.c b/arch/loongarch/kernel/module.c
index 755d91ef8d85..0024bc6c4af1 100644
--- a/arch/loongarch/kernel/module.c
+++ b/arch/loongarch/kernel/module.c
@@ -281,6 +281,79 @@ static int apply_r_larch_add_sub(struct module *mod, u32 *location, Elf_Addr v,
}
}
+static int apply_r_larch_b26(struct module *mod, u32 *location, Elf_Addr v,
+ s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+{
+ ptrdiff_t offset = (void *)v - (void *)location;
+ union loongarch_instruction *insn = (union loongarch_instruction *)location;
+
+ if (offset >= SZ_128M)
+ v = module_emit_plt_entry(mod, v);
+
+ if (offset < -SZ_128M)
+ v = module_emit_plt_entry(mod, v);
+
+ offset = (void *)v - (void *)location;
+
+ if (offset & 3) {
+ pr_err("module %s: jump offset = 0x%llx unaligned! dangerous R_LARCH_B26 (%u) relocation\n",
+ mod->name, (long long)offset, type);
+ return -ENOEXEC;
+ }
+
+ if (!signed_imm_check(offset, 28)) {
+ pr_err("module %s: jump offset = 0x%llx overflow! dangerous R_LARCH_B26 (%u) relocation\n",
+ mod->name, (long long)offset, type);
+ return -ENOEXEC;
+ }
+
+ offset >>= 2;
+ insn->reg0i26_format.immediate_l = offset & 0xffff;
+ insn->reg0i26_format.immediate_h = (offset >> 16) & 0x3ff;
+ return 0;
+}
+
+static int apply_r_larch_pcala(struct module *mod, u32 *location, Elf_Addr v,
+ s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+{
+ union loongarch_instruction *insn = (union loongarch_instruction *)location;
+ /* Use s32 for a sign-extension deliberately. */
+ s32 offset_hi20 = (void *)((v + 0x800) & ~0xfff) -
+ (void *)((Elf_Addr)location & ~0xfff);
+ Elf_Addr anchor = (((Elf_Addr)location) & ~0xfff) + offset_hi20;
+ ptrdiff_t offset_rem = (void *)v - (void *)anchor;
+
+ switch (type) {
+ case R_LARCH_PCALA_HI20:
+ v = offset_hi20 >> 12;
+ break;
+ case R_LARCH_PCALA64_LO20:
+ v = offset_rem >> 32;
+ break;
+ case R_LARCH_PCALA64_HI12:
+ v = offset_rem >> 52;
+ break;
+ default:
+ /* Do nothing. */
+ }
+
+ switch (type) {
+ case R_LARCH_PCALA_HI20:
+ case R_LARCH_PCALA64_LO20:
+ insn->reg1i20_format.immediate = v & 0xfffff;
+ break;
+ case R_LARCH_PCALA_LO12:
+ case R_LARCH_PCALA64_HI12:
+ insn->reg2i12_format.immediate = v & 0xfff;
+ break;
+ default:
+ pr_err("%s: Unsupport relocation type %u\n", mod->name, type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/*
* reloc_handlers_rela() - Apply a particular relocation to a module
* @mod: the module to apply the reloc to
@@ -310,6 +383,8 @@ static reloc_rela_handler reloc_rela_handlers[] = {
[R_LARCH_SOP_SUB ... R_LARCH_SOP_IF_ELSE] = apply_r_larch_sop,
[R_LARCH_SOP_POP_32_S_10_5 ... R_LARCH_SOP_POP_32_U] = apply_r_larch_sop_imm_field,
[R_LARCH_ADD32 ... R_LARCH_SUB64] = apply_r_larch_add_sub,
+ [R_LARCH_B26] = apply_r_larch_b26,
+ [R_LARCH_PCALA_HI20...R_LARCH_PCALA64_HI12] = apply_r_larch_pcala,
};
int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
--
2.37.0
GCC >= 13 and GNU assembler >= 2.40 use these relocations to address
external symbols, so we need to add them.
Let the module loader emit GOT entries for data symbols so we would be
able to handle GOT relocations. The GOT entry is just the data symbol
address.
In module.lds, emit a stub .got section for a section header entry.
The actual content of the entry will be filled at runtime by
module_frob_arch_sections.
Signed-off-by: Xi Ruoyao <[email protected]>
---
arch/loongarch/include/asm/module.h | 23 ++++++++++++
arch/loongarch/include/asm/module.lds.h | 1 +
arch/loongarch/kernel/module-sections.c | 49 +++++++++++++++++++++++--
arch/loongarch/kernel/module.c | 24 ++++++++++++
4 files changed, 94 insertions(+), 3 deletions(-)
diff --git a/arch/loongarch/include/asm/module.h b/arch/loongarch/include/asm/module.h
index 9f6718df1854..76a98a0ab8a0 100644
--- a/arch/loongarch/include/asm/module.h
+++ b/arch/loongarch/include/asm/module.h
@@ -19,6 +19,7 @@ struct mod_section {
struct mod_arch_specific {
struct mod_section plt;
struct mod_section plt_idx;
+ struct mod_section got;
};
struct plt_entry {
@@ -28,11 +29,16 @@ struct plt_entry {
u32 inst_jirl;
};
+struct got_entry {
+ Elf_Addr symbol_addr;
+};
+
struct plt_idx_entry {
unsigned long symbol_addr;
};
Elf_Addr module_emit_plt_entry(struct module *mod, unsigned long val);
+Elf_Addr module_emit_got_entry(struct module *mod, Elf_Addr val);
static inline struct plt_entry emit_plt_entry(unsigned long val)
{
@@ -51,6 +57,11 @@ static inline struct plt_idx_entry emit_plt_idx_entry(unsigned long val)
return (struct plt_idx_entry) { val };
}
+static inline struct got_entry emit_got_entry(Elf_Addr val)
+{
+ return (struct got_entry) { val };
+}
+
static inline int get_plt_idx(unsigned long val, const struct mod_section *sec)
{
int i;
@@ -77,4 +88,16 @@ static inline struct plt_entry *get_plt_entry(unsigned long val,
return plt + plt_idx;
}
+static inline struct got_entry *get_got_entry(Elf_Addr val,
+ const struct mod_section *sec)
+{
+ struct got_entry *got = (struct got_entry *)sec->shdr->sh_addr;
+ int i;
+
+ for (i = 0; i < sec->num_entries; i++)
+ if (got[i].symbol_addr == val)
+ return &got[i];
+ return NULL;
+}
+
#endif /* _ASM_MODULE_H */
diff --git a/arch/loongarch/include/asm/module.lds.h b/arch/loongarch/include/asm/module.lds.h
index 31c1c0db11a3..57bbd0cedd26 100644
--- a/arch/loongarch/include/asm/module.lds.h
+++ b/arch/loongarch/include/asm/module.lds.h
@@ -4,4 +4,5 @@ SECTIONS {
. = ALIGN(4);
.plt : { BYTE(0) }
.plt.idx : { BYTE(0) }
+ .got : { BYTE(0) }
}
diff --git a/arch/loongarch/kernel/module-sections.c b/arch/loongarch/kernel/module-sections.c
index c67b9cb220eb..4c99737cd8dc 100644
--- a/arch/loongarch/kernel/module-sections.c
+++ b/arch/loongarch/kernel/module-sections.c
@@ -33,6 +33,31 @@ Elf_Addr module_emit_plt_entry(struct module *mod, unsigned long val)
return (Elf_Addr)&plt[nr];
}
+Elf_Addr module_emit_got_entry(struct module *mod, Elf_Addr val)
+{
+ struct mod_section *got_sec = &mod->arch.got;
+ int i = got_sec->num_entries;
+ struct got_entry *got = get_got_entry(val, got_sec);
+
+ if (got)
+ return (Elf_Addr)got;
+
+ /* There is no GOT entry existing for val yet. Create a new one. */
+ got = (struct got_entry *)got_sec->shdr->sh_addr;
+ got[i] = emit_got_entry(val);
+
+ got_sec->num_entries++;
+ if (got_sec->num_entries > got_sec->max_entries) {
+ /* This may happen when the module contains a GOT_HI20 without
+ * a paired GOT_LO12. Such a module is broken, reject it.
+ */
+ pr_err("%s: module contains bad GOT relocation\n", mod->name);
+ return 0;
+ }
+
+ return (Elf_Addr)&got[i];
+}
+
static int is_rela_equal(const Elf_Rela *x, const Elf_Rela *y)
{
return x->r_info == y->r_info && x->r_addend == y->r_addend;
@@ -50,7 +75,8 @@ static bool duplicate_rela(const Elf_Rela *rela, int idx)
return false;
}
-static void count_max_entries(Elf_Rela *relas, int num, unsigned int *plts)
+static void count_max_entries(Elf_Rela *relas, int num,
+ unsigned int *plts, unsigned int *gots)
{
unsigned int i, type;
@@ -62,6 +88,10 @@ static void count_max_entries(Elf_Rela *relas, int num, unsigned int *plts)
if (!duplicate_rela(relas, i))
(*plts)++;
break;
+ case R_LARCH_GOT_PC_HI20:
+ if (!duplicate_rela(relas, i))
+ (*gots)++;
+ break;
default:
/* Do nothing. */
}
@@ -71,7 +101,7 @@ static void count_max_entries(Elf_Rela *relas, int num, unsigned int *plts)
int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
char *secstrings, struct module *mod)
{
- unsigned int i, num_plts = 0;
+ unsigned int i, num_plts = 0, num_gots = 0;
/*
* Find the empty .plt sections.
@@ -81,6 +111,8 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
mod->arch.plt.shdr = sechdrs + i;
else if (!strcmp(secstrings + sechdrs[i].sh_name, ".plt.idx"))
mod->arch.plt_idx.shdr = sechdrs + i;
+ else if (!strcmp(secstrings + sechdrs[i].sh_name, ".got"))
+ mod->arch.got.shdr = sechdrs + i;
}
if (!mod->arch.plt.shdr) {
@@ -91,6 +123,10 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
pr_err("%s: module PLT.IDX section(s) missing\n", mod->name);
return -ENOEXEC;
}
+ if (!mod->arch.got.shdr) {
+ pr_err("%s: module GOT section(s) missing\n", mod->name);
+ return -ENOEXEC;
+ }
/* Calculate the maxinum number of entries */
for (i = 0; i < ehdr->e_shnum; i++) {
@@ -105,7 +141,7 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
if (!(dst_sec->sh_flags & SHF_EXECINSTR))
continue;
- count_max_entries(relas, num_rela, &num_plts);
+ count_max_entries(relas, num_rela, &num_plts, &num_gots);
}
mod->arch.plt.shdr->sh_type = SHT_NOBITS;
@@ -122,5 +158,12 @@ int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
mod->arch.plt_idx.num_entries = 0;
mod->arch.plt_idx.max_entries = num_plts;
+ mod->arch.got.shdr->sh_type = SHT_NOBITS;
+ mod->arch.got.shdr->sh_flags = SHF_ALLOC;
+ mod->arch.got.shdr->sh_addralign = L1_CACHE_BYTES;
+ mod->arch.got.shdr->sh_size = (num_gots + 1) * sizeof(struct got_entry);
+ mod->arch.got.num_entries = 0;
+ mod->arch.got.max_entries = num_gots;
+
return 0;
}
diff --git a/arch/loongarch/kernel/module.c b/arch/loongarch/kernel/module.c
index 0024bc6c4af1..46f323845f29 100644
--- a/arch/loongarch/kernel/module.c
+++ b/arch/loongarch/kernel/module.c
@@ -354,6 +354,29 @@ static int apply_r_larch_pcala(struct module *mod, u32 *location, Elf_Addr v,
return 0;
}
+static int apply_r_larch_got_pc(struct module *mod, u32 *location, Elf_Addr v,
+ s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
+{
+ Elf_Addr got = module_emit_got_entry(mod, v);
+
+ if (!got)
+ return -EINVAL;
+
+ switch (type) {
+ case R_LARCH_GOT_PC_LO12:
+ type = R_LARCH_PCALA_LO12;
+ break;
+ case R_LARCH_GOT_PC_HI20:
+ type = R_LARCH_PCALA_HI20;
+ break;
+ default:
+ pr_err("%s: Unsupport relocation type %u\n", mod->name, type);
+ return -EINVAL;
+ }
+
+ return apply_r_larch_pcala(mod, location, got, rela_stack, rela_stack_top, type);
+}
+
/*
* reloc_handlers_rela() - Apply a particular relocation to a module
* @mod: the module to apply the reloc to
@@ -385,6 +408,7 @@ static reloc_rela_handler reloc_rela_handlers[] = {
[R_LARCH_ADD32 ... R_LARCH_SUB64] = apply_r_larch_add_sub,
[R_LARCH_B26] = apply_r_larch_b26,
[R_LARCH_PCALA_HI20...R_LARCH_PCALA64_HI12] = apply_r_larch_pcala,
+ [R_LARCH_GOT_PC_HI20...R_LARCH_GOT_PC_LO12] = apply_r_larch_got_pc,
};
int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
--
2.37.0
If explicit relocation hints is used by the toolchain, -Wa,-mla-*
options will be useless for C code. Only use them for
!CONFIG_AS_HAS_EXPLICIT_RELOCS.
Replace "la" with "la.pcrel" in head.S to keep the semantic consistent
with new and old toolchains for the low level startup code.
Remove -fplt because it's the default for all known LoongArch C
compilers.
The behavior with different assemblers and compilers are summarized in
the following table:
AS has CC has
explicit reloc explicit reloc Behavior
==============================================================
No No Use la.* macros.
No change from Linux 6.0.
--------------------------------------------------------------
No Yes Disable explicit reloc.
No change from Linux 6.0.
--------------------------------------------------------------
Yes No Not supported.
--------------------------------------------------------------
Yes Yes Use explicit relocs.
No -Wa,-mla* options.
==============================================================
Signed-off-by: Xi Ruoyao <[email protected]>
---
arch/loongarch/Makefile | 19 ++++++++++++++++++-
arch/loongarch/kernel/head.S | 10 +++++-----
2 files changed, 23 insertions(+), 6 deletions(-)
diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
index 7051a95f7f31..1563747c4fa8 100644
--- a/arch/loongarch/Makefile
+++ b/arch/loongarch/Makefile
@@ -40,10 +40,27 @@ endif
cflags-y += -G0 -pipe -msoft-float
LDFLAGS_vmlinux += -G0 -static -n -nostdlib
+
+# When the assembler supports explicit relocation hint, we must use it.
+# GCC may have -mexplicit-relocs off by default if it was built with an old
+# assembler, so we force it via an option.
+#
+# When the assembler does not supports explicit relocation hint, we can't use
+# it. Disable it if the compiler supports it.
+#
+# If you've seen "unknown reloc hint" message building the kernel and you are
+# now wondering why "-mexplicit-relocs" is not wrapped with cc-option: the
+# combination of a "new" assembler and "old" compiler is not supported. Either
+# upgrade the compiler or downgrade the assembler.
+ifdef CONFIG_AS_HAS_EXPLICIT_RELOCS
+cflags-y += -mexplicit-relocs
+else
+cflags-y += $(call cc-option,-mno-explicit-relocs)
KBUILD_AFLAGS_KERNEL += -Wa,-mla-global-with-pcrel
KBUILD_CFLAGS_KERNEL += -Wa,-mla-global-with-pcrel
KBUILD_AFLAGS_MODULE += -Wa,-mla-global-with-abs
-KBUILD_CFLAGS_MODULE += -fplt -Wa,-mla-global-with-abs,-mla-local-with-abs
+KBUILD_CFLAGS_MODULE += -Wa,-mla-global-with-abs,-mla-local-with-abs
+endif
cflags-y += -ffreestanding
cflags-y += $(call cc-option, -mno-check-zero-division)
diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
index 01bac62a6442..eb3f641d5915 100644
--- a/arch/loongarch/kernel/head.S
+++ b/arch/loongarch/kernel/head.S
@@ -55,17 +55,17 @@ SYM_CODE_START(kernel_entry) # kernel entry point
li.w t0, 0x00 # FPE=0, SXE=0, ASXE=0, BTE=0
csrwr t0, LOONGARCH_CSR_EUEN
- la t0, __bss_start # clear .bss
+ la.pcrel t0, __bss_start # clear .bss
st.d zero, t0, 0
- la t1, __bss_stop - LONGSIZE
+ la.pcrel t1, __bss_stop - LONGSIZE
1:
addi.d t0, t0, LONGSIZE
st.d zero, t0, 0
bne t0, t1, 1b
- la t0, fw_arg0
+ la.pcrel t0, fw_arg0
st.d a0, t0, 0 # firmware arguments
- la t0, fw_arg1
+ la.pcrel t0, fw_arg1
st.d a1, t0, 0
/* KSave3 used for percpu base, initialized as 0 */
@@ -73,7 +73,7 @@ SYM_CODE_START(kernel_entry) # kernel entry point
/* GPR21 used for percpu base (runtime), initialized as 0 */
move u0, zero
- la tp, init_thread_union
+ la.pcrel tp, init_thread_union
/* Set the SP after an empty pt_regs. */
PTR_LI sp, (_THREAD_SIZE - 32 - PT_SIZE)
PTR_ADD sp, sp, tp
--
2.37.0
These relocation types are used by GNU binutils >= 2.40 and GCC >= 13.
Add their definitions so we will be able to use them in later patches.
Link: https://github.com/loongson/LoongArch-Documentation/pull/57
Signed-off-by: Xi Ruoyao <[email protected]>
---
arch/loongarch/include/asm/elf.h | 37 ++++++++++++++++++++++++++++++++
arch/loongarch/kernel/module.c | 2 +-
2 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/arch/loongarch/include/asm/elf.h b/arch/loongarch/include/asm/elf.h
index 5f3ff4781fda..7af0cebf28d7 100644
--- a/arch/loongarch/include/asm/elf.h
+++ b/arch/loongarch/include/asm/elf.h
@@ -74,6 +74,43 @@
#define R_LARCH_SUB64 56
#define R_LARCH_GNU_VTINHERIT 57
#define R_LARCH_GNU_VTENTRY 58
+#define R_LARCH_B16 64
+#define R_LARCH_B21 65
+#define R_LARCH_B26 66
+#define R_LARCH_ABS_HI20 67
+#define R_LARCH_ABS_LO12 68
+#define R_LARCH_ABS64_LO20 69
+#define R_LARCH_ABS64_HI12 70
+#define R_LARCH_PCALA_HI20 71
+#define R_LARCH_PCALA_LO12 72
+#define R_LARCH_PCALA64_LO20 73
+#define R_LARCH_PCALA64_HI12 74
+#define R_LARCH_GOT_PC_HI20 75
+#define R_LARCH_GOT_PC_LO12 76
+#define R_LARCH_GOT64_PC_LO20 77
+#define R_LARCH_GOT64_PC_HI12 78
+#define R_LARCH_GOT_HI20 79
+#define R_LARCH_GOT_LO12 80
+#define R_LARCH_GOT64_LO20 81
+#define R_LARCH_GOT64_HI12 82
+#define R_LARCH_TLS_LE_HI20 83
+#define R_LARCH_TLS_LE_LO12 84
+#define R_LARCH_TLS_LE64_LO20 85
+#define R_LARCH_TLS_LE64_HI12 86
+#define R_LARCH_TLS_IE_PC_HI20 87
+#define R_LARCH_TLS_IE_PC_LO12 88
+#define R_LARCH_TLS_IE64_PC_LO20 89
+#define R_LARCH_TLS_IE64_PC_HI12 90
+#define R_LARCH_TLS_IE_HI20 91
+#define R_LARCH_TLS_IE_LO12 92
+#define R_LARCH_TLS_IE64_LO20 93
+#define R_LARCH_TLS_IE64_HI12 94
+#define R_LARCH_TLS_LD_PC_HI20 95
+#define R_LARCH_TLS_LD_HI20 96
+#define R_LARCH_TLS_GD_PC_HI20 97
+#define R_LARCH_TLS_GD_HI20 98
+#define R_LARCH_32_PCREL 99
+#define R_LARCH_RELAX 100
#ifndef ELF_ARCH
diff --git a/arch/loongarch/kernel/module.c b/arch/loongarch/kernel/module.c
index 638427ff0d51..755d91ef8d85 100644
--- a/arch/loongarch/kernel/module.c
+++ b/arch/loongarch/kernel/module.c
@@ -296,7 +296,7 @@ typedef int (*reloc_rela_handler)(struct module *mod, u32 *location, Elf_Addr v,
/* The handlers for known reloc types */
static reloc_rela_handler reloc_rela_handlers[] = {
- [R_LARCH_NONE ... R_LARCH_SUB64] = apply_r_larch_error,
+ [R_LARCH_NONE ... R_LARCH_RELAX] = apply_r_larch_error,
[R_LARCH_NONE] = apply_r_larch_none,
[R_LARCH_32] = apply_r_larch_32,
--
2.37.0
GNU as >= 2.40 and GCC >= 13 will support using explicit relocation
hints in the assembly code, instead of la.* macros. The usage of
explicit relocation hints can improve code generation so it's enabled
by default by GCC >= 13.
Introduce CONFIG_AS_HAS_EXPLICIT_RELOCS as the switch for
"use explicit relocation hints or not."
Signed-off-by: Xi Ruoyao <[email protected]>
---
arch/loongarch/Kconfig | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index d3ce96a1a744..0721b4b2207a 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -204,6 +204,9 @@ config SCHED_OMIT_FRAME_POINTER
bool
default y
+config AS_HAS_EXPLICIT_RELOCS
+ def_bool $(as-instr,x:pcalau12i \$t0$(comma)%pc_hi20(x))
+
menu "Kernel type and options"
source "kernel/Kconfig.hz"
--
2.37.0
On Mon, 2022-08-29 at 21:31 +0800, Xi Ruoyao wrote:
> Changes from v5 to v6:
>
> - Restore version number.
> - Rename CONFIG_CC_HAS_EXPLICIT_RELOCS to
> CONFIG_AS_HAS_EXPLICIT_RELOCS.
> It now only checks assembler.
> - No longer support "old GCC with new Binutils", so R_LARCH_ABS* is
> dropped.
> - "Old GCC with old Binutils" is still supported until Arnd ack.
> longer support it.
^^^^
This line should be removed :(.
> - "New GCC with old Binutils" is still supported as it does not
> require additional code.
> - Remove "cc-option" around "-mexplicit-relocs". For unsupported
> "old GCC with new Binutils" combination, forcing -mexplicit-relocs
> makes assembling fail, instead of silently producing unloadable
> modules.
> - Move the error report for "lacking model attribute" into Makefile.
> - Squash the two patches for R_LARCH_B26 and R_LARCH_PCALA* into one.
--
Xi Ruoyao <[email protected]>
School of Aerospace Science and Technology, Xidian University
On Mon, 2022-08-29 at 21:31 +0800, Xi Ruoyao wrote:
> diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
> index 1563747c4fa8..593818a61741 100644
> --- a/arch/loongarch/Makefile
> +++ b/arch/loongarch/Makefile
> @@ -53,6 +53,9 @@ LDFLAGS_vmlinux += -G0 -static -n -nostdlib
> # combination of a "new" assembler and "old" compiler is not supported. Either
> # upgrade the compiler or downgrade the assembler.
> ifdef CONFIG_AS_HAS_EXPLICIT_RELOCS
> +ifeq ($(shell echo '__has_attribute(model)' | $(CC) -E -P - 2> /dev/null), 0)
> +$(error "C compiler must support model attribute if using explicit relocs")
> +endif
Self review:
I'm wondering if we really need this thing... There won't be a GCC
version released with explicit relocation but without model attribute
(GCC 13 starts to support them both).
But without a check, if someone uses an early GCC 13 snapshot and
ignores the -Wattributes warning, the system will suddenly blow up
loading a module with per-CPU variable defined.
Maybe "-Werror=attributes" is better, but is it OK to add a -Werror=
option for entire Linux tree?
> cflags-y += -mexplicit-relocs
> else
> cflags-y += $(call cc-option,-mno-explicit-relocs)
--
Xi Ruoyao <[email protected]>
School of Aerospace Science and Technology, Xidian University
Hi, Ruoyao,
This version looks good to me, only some small issues. Thank you very much.
Huacai
On Mon, Aug 29, 2022 at 10:57 PM Xi Ruoyao <[email protected]> wrote:
>
> On Mon, 2022-08-29 at 21:31 +0800, Xi Ruoyao wrote:
>
> > Changes from v5 to v6:
> >
> > - Restore version number.
> > - Rename CONFIG_CC_HAS_EXPLICIT_RELOCS to
> > CONFIG_AS_HAS_EXPLICIT_RELOCS.
> > It now only checks assembler.
> > - No longer support "old GCC with new Binutils", so R_LARCH_ABS* is
> > dropped.
> > - "Old GCC with old Binutils" is still supported until Arnd ack.
>
> > longer support it.
> ^^^^
> This line should be removed :(.
>
> > - "New GCC with old Binutils" is still supported as it does not
> > require additional code.
> > - Remove "cc-option" around "-mexplicit-relocs". For unsupported
> > "old GCC with new Binutils" combination, forcing -mexplicit-relocs
> > makes assembling fail, instead of silently producing unloadable
> > modules.
> > - Move the error report for "lacking model attribute" into Makefile.
> > - Squash the two patches for R_LARCH_B26 and R_LARCH_PCALA* into one.
>
> --
> Xi Ruoyao <[email protected]>
> School of Aerospace Science and Technology, Xidian University
Hi, Ruoyao,
On Mon, Aug 29, 2022 at 9:35 PM Xi Ruoyao <[email protected]> wrote:
>
> Binutils >= 2.40 uses R_LARCH_B26 instead of R_LARCH_SOP_PUSH_PLT_PCREL,
> and R_LARCH_PCALA* instead of R_LARCH_SOP_PUSH_PCREL.
>
> Handle R_LARCH_B26 and R_LARCH_PCALA* in the module loader. For
> R_LARCH_B26, also create a PLT entry as needed.
>
> Signed-off-by: Xi Ruoyao <[email protected]>
> ---
> arch/loongarch/kernel/module-sections.c | 7 ++-
> arch/loongarch/kernel/module.c | 75 +++++++++++++++++++++++++
> 2 files changed, 81 insertions(+), 1 deletion(-)
>
> diff --git a/arch/loongarch/kernel/module-sections.c b/arch/loongarch/kernel/module-sections.c
> index 6d498288977d..c67b9cb220eb 100644
> --- a/arch/loongarch/kernel/module-sections.c
> +++ b/arch/loongarch/kernel/module-sections.c
> @@ -56,9 +56,14 @@ static void count_max_entries(Elf_Rela *relas, int num, unsigned int *plts)
>
> for (i = 0; i < num; i++) {
> type = ELF_R_TYPE(relas[i].r_info);
> - if (type == R_LARCH_SOP_PUSH_PLT_PCREL) {
> + switch (type) {
> + case R_LARCH_SOP_PUSH_PLT_PCREL:
> + case R_LARCH_B26:
> if (!duplicate_rela(relas, i))
> (*plts)++;
> + break;
> + default:
> + /* Do nothing. */
> }
> }
> }
> diff --git a/arch/loongarch/kernel/module.c b/arch/loongarch/kernel/module.c
> index 755d91ef8d85..0024bc6c4af1 100644
> --- a/arch/loongarch/kernel/module.c
> +++ b/arch/loongarch/kernel/module.c
> @@ -281,6 +281,79 @@ static int apply_r_larch_add_sub(struct module *mod, u32 *location, Elf_Addr v,
> }
> }
>
> +static int apply_r_larch_b26(struct module *mod, u32 *location, Elf_Addr v,
> + s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
> +{
> + ptrdiff_t offset = (void *)v - (void *)location;
> + union loongarch_instruction *insn = (union loongarch_instruction *)location;
> +
> + if (offset >= SZ_128M)
> + v = module_emit_plt_entry(mod, v);
> +
> + if (offset < -SZ_128M)
> + v = module_emit_plt_entry(mod, v);
> +
> + offset = (void *)v - (void *)location;
> +
> + if (offset & 3) {
> + pr_err("module %s: jump offset = 0x%llx unaligned! dangerous R_LARCH_B26 (%u) relocation\n",
> + mod->name, (long long)offset, type);
> + return -ENOEXEC;
> + }
> +
> + if (!signed_imm_check(offset, 28)) {
> + pr_err("module %s: jump offset = 0x%llx overflow! dangerous R_LARCH_B26 (%u) relocation\n",
> + mod->name, (long long)offset, type);
> + return -ENOEXEC;
> + }
> +
> + offset >>= 2;
> + insn->reg0i26_format.immediate_l = offset & 0xffff;
> + insn->reg0i26_format.immediate_h = (offset >> 16) & 0x3ff;
> + return 0;
> +}
> +
> +static int apply_r_larch_pcala(struct module *mod, u32 *location, Elf_Addr v,
> + s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
> +{
> + union loongarch_instruction *insn = (union loongarch_instruction *)location;
> + /* Use s32 for a sign-extension deliberately. */
> + s32 offset_hi20 = (void *)((v + 0x800) & ~0xfff) -
> + (void *)((Elf_Addr)location & ~0xfff);
> + Elf_Addr anchor = (((Elf_Addr)location) & ~0xfff) + offset_hi20;
> + ptrdiff_t offset_rem = (void *)v - (void *)anchor;
> +
> + switch (type) {
> + case R_LARCH_PCALA_HI20:
> + v = offset_hi20 >> 12;
> + break;
> + case R_LARCH_PCALA64_LO20:
> + v = offset_rem >> 32;
> + break;
> + case R_LARCH_PCALA64_HI12:
> + v = offset_rem >> 52;
> + break;
> + default:
> + /* Do nothing. */
> + }
> +
> + switch (type) {
> + case R_LARCH_PCALA_HI20:
> + case R_LARCH_PCALA64_LO20:
> + insn->reg1i20_format.immediate = v & 0xfffff;
> + break;
> + case R_LARCH_PCALA_LO12:
> + case R_LARCH_PCALA64_HI12:
> + insn->reg2i12_format.immediate = v & 0xfff;
> + break;
> + default:
> + pr_err("%s: Unsupport relocation type %u\n", mod->name, type);
> + return -EINVAL;
> + }
Can we merge the two switch here?
Huacai
> +
> + return 0;
> +}
> +
> /*
> * reloc_handlers_rela() - Apply a particular relocation to a module
> * @mod: the module to apply the reloc to
> @@ -310,6 +383,8 @@ static reloc_rela_handler reloc_rela_handlers[] = {
> [R_LARCH_SOP_SUB ... R_LARCH_SOP_IF_ELSE] = apply_r_larch_sop,
> [R_LARCH_SOP_POP_32_S_10_5 ... R_LARCH_SOP_POP_32_U] = apply_r_larch_sop_imm_field,
> [R_LARCH_ADD32 ... R_LARCH_SUB64] = apply_r_larch_add_sub,
> + [R_LARCH_B26] = apply_r_larch_b26,
> + [R_LARCH_PCALA_HI20...R_LARCH_PCALA64_HI12] = apply_r_larch_pcala,
> };
>
> int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
> --
> 2.37.0
>
>
Hi, Ruoyao,
On Mon, Aug 29, 2022 at 9:35 PM Xi Ruoyao <[email protected]> wrote:
>
> If explicit relocation hints is used by the toolchain, -Wa,-mla-*
> options will be useless for C code. Only use them for
> !CONFIG_AS_HAS_EXPLICIT_RELOCS.
>
> Replace "la" with "la.pcrel" in head.S to keep the semantic consistent
> with new and old toolchains for the low level startup code.
>
> Remove -fplt because it's the default for all known LoongArch C
> compilers.
>
> The behavior with different assemblers and compilers are summarized in
> the following table:
>
> AS has CC has
> explicit reloc explicit reloc Behavior
> ==============================================================
> No No Use la.* macros.
> No change from Linux 6.0.
> --------------------------------------------------------------
> No Yes Disable explicit reloc.
> No change from Linux 6.0.
> --------------------------------------------------------------
> Yes No Not supported.
> --------------------------------------------------------------
> Yes Yes Use explicit relocs.
> No -Wa,-mla* options.
> ==============================================================
>
> Signed-off-by: Xi Ruoyao <[email protected]>
> ---
> arch/loongarch/Makefile | 19 ++++++++++++++++++-
> arch/loongarch/kernel/head.S | 10 +++++-----
> 2 files changed, 23 insertions(+), 6 deletions(-)
>
> diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
> index 7051a95f7f31..1563747c4fa8 100644
> --- a/arch/loongarch/Makefile
> +++ b/arch/loongarch/Makefile
> @@ -40,10 +40,27 @@ endif
>
> cflags-y += -G0 -pipe -msoft-float
> LDFLAGS_vmlinux += -G0 -static -n -nostdlib
> +
> +# When the assembler supports explicit relocation hint, we must use it.
> +# GCC may have -mexplicit-relocs off by default if it was built with an old
> +# assembler, so we force it via an option.
> +#
> +# When the assembler does not supports explicit relocation hint, we can't use
> +# it. Disable it if the compiler supports it.
> +#
> +# If you've seen "unknown reloc hint" message building the kernel and you are
> +# now wondering why "-mexplicit-relocs" is not wrapped with cc-option: the
> +# combination of a "new" assembler and "old" compiler is not supported. Either
> +# upgrade the compiler or downgrade the assembler.
> +ifdef CONFIG_AS_HAS_EXPLICIT_RELOCS
> +cflags-y += -mexplicit-relocs
> +else
> +cflags-y += $(call cc-option,-mno-explicit-relocs)
> KBUILD_AFLAGS_KERNEL += -Wa,-mla-global-with-pcrel
> KBUILD_CFLAGS_KERNEL += -Wa,-mla-global-with-pcrel
> KBUILD_AFLAGS_MODULE += -Wa,-mla-global-with-abs
> -KBUILD_CFLAGS_MODULE += -fplt -Wa,-mla-global-with-abs,-mla-local-with-abs
> +KBUILD_CFLAGS_MODULE += -Wa,-mla-global-with-abs,-mla-local-with-abs
Though -fplt is the default, keep it can make code clearer.
Huacai
> +endif
>
> cflags-y += -ffreestanding
> cflags-y += $(call cc-option, -mno-check-zero-division)
> diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
> index 01bac62a6442..eb3f641d5915 100644
> --- a/arch/loongarch/kernel/head.S
> +++ b/arch/loongarch/kernel/head.S
> @@ -55,17 +55,17 @@ SYM_CODE_START(kernel_entry) # kernel entry point
> li.w t0, 0x00 # FPE=0, SXE=0, ASXE=0, BTE=0
> csrwr t0, LOONGARCH_CSR_EUEN
>
> - la t0, __bss_start # clear .bss
> + la.pcrel t0, __bss_start # clear .bss
> st.d zero, t0, 0
> - la t1, __bss_stop - LONGSIZE
> + la.pcrel t1, __bss_stop - LONGSIZE
> 1:
> addi.d t0, t0, LONGSIZE
> st.d zero, t0, 0
> bne t0, t1, 1b
>
> - la t0, fw_arg0
> + la.pcrel t0, fw_arg0
> st.d a0, t0, 0 # firmware arguments
> - la t0, fw_arg1
> + la.pcrel t0, fw_arg1
> st.d a1, t0, 0
>
> /* KSave3 used for percpu base, initialized as 0 */
> @@ -73,7 +73,7 @@ SYM_CODE_START(kernel_entry) # kernel entry point
> /* GPR21 used for percpu base (runtime), initialized as 0 */
> move u0, zero
>
> - la tp, init_thread_union
> + la.pcrel tp, init_thread_union
> /* Set the SP after an empty pt_regs. */
> PTR_LI sp, (_THREAD_SIZE - 32 - PT_SIZE)
> PTR_ADD sp, sp, tp
> --
> 2.37.0
>
>
Hi, Ruoyao,
On Mon, Aug 29, 2022 at 11:02 PM Xi Ruoyao <[email protected]> wrote:
>
> On Mon, 2022-08-29 at 21:31 +0800, Xi Ruoyao wrote:
> > diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile
> > index 1563747c4fa8..593818a61741 100644
> > --- a/arch/loongarch/Makefile
> > +++ b/arch/loongarch/Makefile
> > @@ -53,6 +53,9 @@ LDFLAGS_vmlinux += -G0 -static -n -nostdlib
> > # combination of a "new" assembler and "old" compiler is not supported. Either
> > # upgrade the compiler or downgrade the assembler.
> > ifdef CONFIG_AS_HAS_EXPLICIT_RELOCS
> > +ifeq ($(shell echo '__has_attribute(model)' | $(CC) -E -P - 2> /dev/null), 0)
> > +$(error "C compiler must support model attribute if using explicit relocs")
> > +endif
>
> Self review:
>
> I'm wondering if we really need this thing... There won't be a GCC
> version released with explicit relocation but without model attribute
> (GCC 13 starts to support them both).
>
> But without a check, if someone uses an early GCC 13 snapshot and
> ignores the -Wattributes warning, the system will suddenly blow up
> loading a module with per-CPU variable defined.
>
> Maybe "-Werror=attributes" is better, but is it OK to add a -Werror=
> option for entire Linux tree?
I think we can remove it entirely, and then this patch seems can be
squashed into patch 2.
Huacai
>
> > cflags-y += -mexplicit-relocs
> > else
> > cflags-y += $(call cc-option,-mno-explicit-relocs)
>
> --
> Xi Ruoyao <[email protected]>
> School of Aerospace Science and Technology, Xidian University
>
On 2022/8/29 23:08, Huacai Chen wrote:
> [snip]
>> +static int apply_r_larch_pcala(struct module *mod, u32 *location, Elf_Addr v,
>> + s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
>> +{
>> + union loongarch_instruction *insn = (union loongarch_instruction *)location;
>> + /* Use s32 for a sign-extension deliberately. */
>> + s32 offset_hi20 = (void *)((v + 0x800) & ~0xfff) -
>> + (void *)((Elf_Addr)location & ~0xfff);
>> + Elf_Addr anchor = (((Elf_Addr)location) & ~0xfff) + offset_hi20;
>> + ptrdiff_t offset_rem = (void *)v - (void *)anchor;
>> +
>> + switch (type) {
>> + case R_LARCH_PCALA_HI20:
>> + v = offset_hi20 >> 12;
>> + break;
>> + case R_LARCH_PCALA64_LO20:
>> + v = offset_rem >> 32;
>> + break;
>> + case R_LARCH_PCALA64_HI12:
>> + v = offset_rem >> 52;
>> + break;
>> + default:
>> + /* Do nothing. */
>> + }
>> +
>> + switch (type) {
>> + case R_LARCH_PCALA_HI20:
>> + case R_LARCH_PCALA64_LO20:
>> + insn->reg1i20_format.immediate = v & 0xfffff;
>> + break;
>> + case R_LARCH_PCALA_LO12:
>> + case R_LARCH_PCALA64_HI12:
>> + insn->reg2i12_format.immediate = v & 0xfff;
>> + break;
>> + default:
>> + pr_err("%s: Unsupport relocation type %u\n", mod->name, type);
>> + return -EINVAL;
>> + }
> Can we merge the two switch here?
IMO leaving as-is or even splitting into two functions would be
acceptable, as the two switches are performing two different things --
namely "adjustFixupValue" (in LLVM-speak) and actually inserting the
value into the insn word. But an argument for merging the two can be
made too, because the v2.00 reloc types are purposely designed with
unique use case for each, meaning there is actually no flexibility in
between the fixup value's calculation and application. So I think this
eventually comes down to coder's preference?
--
WANG "xen0n" Xuerui
Linux/LoongArch mailing list: https://lore.kernel.org/loongarch/
On Tue, Aug 30, 2022 at 9:42 AM WANG Xuerui <[email protected]> wrote:
>
> On 2022/8/29 23:08, Huacai Chen wrote:
> > [snip]
> >> +static int apply_r_larch_pcala(struct module *mod, u32 *location, Elf_Addr v,
> >> + s64 *rela_stack, size_t *rela_stack_top, unsigned int type)
> >> +{
> >> + union loongarch_instruction *insn = (union loongarch_instruction *)location;
> >> + /* Use s32 for a sign-extension deliberately. */
> >> + s32 offset_hi20 = (void *)((v + 0x800) & ~0xfff) -
> >> + (void *)((Elf_Addr)location & ~0xfff);
> >> + Elf_Addr anchor = (((Elf_Addr)location) & ~0xfff) + offset_hi20;
> >> + ptrdiff_t offset_rem = (void *)v - (void *)anchor;
> >> +
> >> + switch (type) {
> >> + case R_LARCH_PCALA_HI20:
> >> + v = offset_hi20 >> 12;
> >> + break;
> >> + case R_LARCH_PCALA64_LO20:
> >> + v = offset_rem >> 32;
> >> + break;
> >> + case R_LARCH_PCALA64_HI12:
> >> + v = offset_rem >> 52;
> >> + break;
> >> + default:
> >> + /* Do nothing. */
> >> + }
> >> +
> >> + switch (type) {
> >> + case R_LARCH_PCALA_HI20:
> >> + case R_LARCH_PCALA64_LO20:
> >> + insn->reg1i20_format.immediate = v & 0xfffff;
> >> + break;
> >> + case R_LARCH_PCALA_LO12:
> >> + case R_LARCH_PCALA64_HI12:
> >> + insn->reg2i12_format.immediate = v & 0xfff;
> >> + break;
> >> + default:
> >> + pr_err("%s: Unsupport relocation type %u\n", mod->name, type);
> >> + return -EINVAL;
> >> + }
> > Can we merge the two switch here?
>
> IMO leaving as-is or even splitting into two functions would be
> acceptable, as the two switches are performing two different things --
> namely "adjustFixupValue" (in LLVM-speak) and actually inserting the
> value into the insn word. But an argument for merging the two can be
> made too, because the v2.00 reloc types are purposely designed with
> unique use case for each, meaning there is actually no flexibility in
> between the fixup value's calculation and application. So I think this
> eventually comes down to coder's preference?
Merging them can just make me understand the logic better, and save
some lines. :)
Huacai
>
> --
> WANG "xen0n" Xuerui
>
> Linux/LoongArch mailing list: https://lore.kernel.org/loongarch/
>