hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/arch/riscv/kernel/module.c
....@@ -1,13 +1,5 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
2
- * This program is free software; you can redistribute it and/or modify
3
- * it under the terms of the GNU General Public License as published by
4
- * the Free Software Foundation; either version 2 of the License, or
5
- * (at your option) any later version.
6
- *
7
- * This program is distributed in the hope that it will be useful,
8
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
- * GNU General Public License for more details.
113 *
124 * Copyright (C) 2017 Zihao Yu
135 */
....@@ -18,8 +10,21 @@
1810 #include <linux/moduleloader.h>
1911 #include <linux/vmalloc.h>
2012 #include <linux/sizes.h>
21
-#include <asm/pgtable.h>
13
+#include <linux/pgtable.h>
2214 #include <asm/sections.h>
15
+
16
+/*
17
+ * The auipc+jalr instruction pair can reach any PC-relative offset
18
+ * in the range [-2^31 - 2^11, 2^31 - 2^11)
19
+ */
20
+static bool riscv_insn_valid_32bit_offset(ptrdiff_t val)
21
+{
22
+#ifdef CONFIG_32BIT
23
+ return true;
24
+#else
25
+ return (-(1L << 31) - (1L << 11)) <= val && val < ((1L << 31) - (1L << 11));
26
+#endif
27
+}
2328
2429 static int apply_r_riscv_32_rela(struct module *me, u32 *location, Elf_Addr v)
2530 {
....@@ -103,7 +108,7 @@
103108 ptrdiff_t offset = (void *)v - (void *)location;
104109 s32 hi20;
105110
106
- if (offset != (s32)offset) {
111
+ if (!riscv_insn_valid_32bit_offset(offset)) {
107112 pr_err(
108113 "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
109114 me->name, (long long)v, location);
....@@ -145,7 +150,7 @@
145150 {
146151 s32 hi20;
147152
148
- if (IS_ENABLED(CMODEL_MEDLOW)) {
153
+ if (IS_ENABLED(CONFIG_CMODEL_MEDLOW)) {
149154 pr_err(
150155 "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
151156 me->name, (long long)v, location);
....@@ -205,10 +210,9 @@
205210 Elf_Addr v)
206211 {
207212 ptrdiff_t offset = (void *)v - (void *)location;
208
- s32 fill_v = offset;
209213 u32 hi20, lo12;
210214
211
- if (offset != fill_v) {
215
+ if (!riscv_insn_valid_32bit_offset(offset)) {
212216 /* Only emit the plt entry if offset over 32-bit range */
213217 if (IS_ENABLED(CONFIG_MODULE_SECTIONS)) {
214218 offset = module_emit_plt_entry(me, v);
....@@ -232,10 +236,9 @@
232236 Elf_Addr v)
233237 {
234238 ptrdiff_t offset = (void *)v - (void *)location;
235
- s32 fill_v = offset;
236239 u32 hi20, lo12;
237240
238
- if (offset != fill_v) {
241
+ if (!riscv_insn_valid_32bit_offset(offset)) {
239242 pr_err(
240243 "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
241244 me->name, (long long)v, location);
....@@ -271,10 +274,24 @@
271274 return 0;
272275 }
273276
277
+static int apply_r_riscv_add64_rela(struct module *me, u32 *location,
278
+ Elf_Addr v)
279
+{
280
+ *(u64 *)location += (u64)v;
281
+ return 0;
282
+}
283
+
274284 static int apply_r_riscv_sub32_rela(struct module *me, u32 *location,
275285 Elf_Addr v)
276286 {
277287 *(u32 *)location -= (u32)v;
288
+ return 0;
289
+}
290
+
291
+static int apply_r_riscv_sub64_rela(struct module *me, u32 *location,
292
+ Elf_Addr v)
293
+{
294
+ *(u64 *)location -= (u64)v;
278295 return 0;
279296 }
280297
....@@ -298,7 +315,9 @@
298315 [R_RISCV_RELAX] = apply_r_riscv_relax_rela,
299316 [R_RISCV_ALIGN] = apply_r_riscv_align_rela,
300317 [R_RISCV_ADD32] = apply_r_riscv_add32_rela,
318
+ [R_RISCV_ADD64] = apply_r_riscv_add64_rela,
301319 [R_RISCV_SUB32] = apply_r_riscv_sub32_rela,
320
+ [R_RISCV_SUB64] = apply_r_riscv_sub64_rela,
302321 };
303322
304323 int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
....@@ -327,8 +346,8 @@
327346 /* Ignore unresolved weak symbol */
328347 if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
329348 continue;
330
- pr_warning("%s: Unknown symbol %s\n",
331
- me->name, strtab + sym->st_name);
349
+ pr_warn("%s: Unknown symbol %s\n",
350
+ me->name, strtab + sym->st_name);
332351 return -ENOENT;
333352 }
334353