Skip to content

Commit 8cbe0ac

Browse files
esmilpalmer-dabbelt
authored andcommitted
riscv: Avoid unaligned access when relocating modules
With the C-extension regular 32bit instructions are not necessarily aligned on 4-byte boundaries. RISC-V instructions are in fact an ordered list of 16bit little-endian "parcels", so access the instruction as such. This should also make the code work in case someone builds a big-endian RISC-V machine. Signed-off-by: Emil Renner Berthing <[email protected]> Signed-off-by: Charlie Jenkins <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent 0bb80ec commit 8cbe0ac

File tree

1 file changed

+81
-76
lines changed

1 file changed

+81
-76
lines changed

arch/riscv/kernel/module.c

Lines changed: 81 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -27,68 +27,90 @@ static bool riscv_insn_valid_32bit_offset(ptrdiff_t val)
2727
#endif
2828
}
2929

30-
static int apply_r_riscv_32_rela(struct module *me, u32 *location, Elf_Addr v)
30+
static int riscv_insn_rmw(void *location, u32 keep, u32 set)
31+
{
32+
u16 *parcel = location;
33+
u32 insn = (u32)le16_to_cpu(parcel[0]) | (u32)le16_to_cpu(parcel[1]) << 16;
34+
35+
insn &= keep;
36+
insn |= set;
37+
38+
parcel[0] = cpu_to_le16(insn);
39+
parcel[1] = cpu_to_le16(insn >> 16);
40+
return 0;
41+
}
42+
43+
static int riscv_insn_rvc_rmw(void *location, u16 keep, u16 set)
44+
{
45+
u16 *parcel = location;
46+
u16 insn = le16_to_cpu(*parcel);
47+
48+
insn &= keep;
49+
insn |= set;
50+
51+
*parcel = cpu_to_le16(insn);
52+
return 0;
53+
}
54+
55+
static int apply_r_riscv_32_rela(struct module *me, void *location, Elf_Addr v)
3156
{
3257
if (v != (u32)v) {
3358
pr_err("%s: value %016llx out of range for 32-bit field\n",
3459
me->name, (long long)v);
3560
return -EINVAL;
3661
}
37-
*location = v;
62+
*(u32 *)location = v;
3863
return 0;
3964
}
4065

41-
static int apply_r_riscv_64_rela(struct module *me, u32 *location, Elf_Addr v)
66+
static int apply_r_riscv_64_rela(struct module *me, void *location, Elf_Addr v)
4267
{
4368
*(u64 *)location = v;
4469
return 0;
4570
}
4671

47-
static int apply_r_riscv_branch_rela(struct module *me, u32 *location,
72+
static int apply_r_riscv_branch_rela(struct module *me, void *location,
4873
Elf_Addr v)
4974
{
50-
ptrdiff_t offset = (void *)v - (void *)location;
75+
ptrdiff_t offset = (void *)v - location;
5176
u32 imm12 = (offset & 0x1000) << (31 - 12);
5277
u32 imm11 = (offset & 0x800) >> (11 - 7);
5378
u32 imm10_5 = (offset & 0x7e0) << (30 - 10);
5479
u32 imm4_1 = (offset & 0x1e) << (11 - 4);
5580

56-
*location = (*location & 0x1fff07f) | imm12 | imm11 | imm10_5 | imm4_1;
57-
return 0;
81+
return riscv_insn_rmw(location, 0x1fff07f, imm12 | imm11 | imm10_5 | imm4_1);
5882
}
5983

60-
static int apply_r_riscv_jal_rela(struct module *me, u32 *location,
84+
static int apply_r_riscv_jal_rela(struct module *me, void *location,
6185
Elf_Addr v)
6286
{
63-
ptrdiff_t offset = (void *)v - (void *)location;
87+
ptrdiff_t offset = (void *)v - location;
6488
u32 imm20 = (offset & 0x100000) << (31 - 20);
6589
u32 imm19_12 = (offset & 0xff000);
6690
u32 imm11 = (offset & 0x800) << (20 - 11);
6791
u32 imm10_1 = (offset & 0x7fe) << (30 - 10);
6892

69-
*location = (*location & 0xfff) | imm20 | imm19_12 | imm11 | imm10_1;
70-
return 0;
93+
return riscv_insn_rmw(location, 0xfff, imm20 | imm19_12 | imm11 | imm10_1);
7194
}
7295

73-
static int apply_r_riscv_rvc_branch_rela(struct module *me, u32 *location,
96+
static int apply_r_riscv_rvc_branch_rela(struct module *me, void *location,
7497
Elf_Addr v)
7598
{
76-
ptrdiff_t offset = (void *)v - (void *)location;
99+
ptrdiff_t offset = (void *)v - location;
77100
u16 imm8 = (offset & 0x100) << (12 - 8);
78101
u16 imm7_6 = (offset & 0xc0) >> (6 - 5);
79102
u16 imm5 = (offset & 0x20) >> (5 - 2);
80103
u16 imm4_3 = (offset & 0x18) << (12 - 5);
81104
u16 imm2_1 = (offset & 0x6) << (12 - 10);
82105

83-
*(u16 *)location = (*(u16 *)location & 0xe383) |
84-
imm8 | imm7_6 | imm5 | imm4_3 | imm2_1;
85-
return 0;
106+
return riscv_insn_rvc_rmw(location, 0xe383,
107+
imm8 | imm7_6 | imm5 | imm4_3 | imm2_1);
86108
}
87109

88-
static int apply_r_riscv_rvc_jump_rela(struct module *me, u32 *location,
110+
static int apply_r_riscv_rvc_jump_rela(struct module *me, void *location,
89111
Elf_Addr v)
90112
{
91-
ptrdiff_t offset = (void *)v - (void *)location;
113+
ptrdiff_t offset = (void *)v - location;
92114
u16 imm11 = (offset & 0x800) << (12 - 11);
93115
u16 imm10 = (offset & 0x400) >> (10 - 8);
94116
u16 imm9_8 = (offset & 0x300) << (12 - 11);
@@ -98,16 +120,14 @@ static int apply_r_riscv_rvc_jump_rela(struct module *me, u32 *location,
98120
u16 imm4 = (offset & 0x10) << (12 - 5);
99121
u16 imm3_1 = (offset & 0xe) << (12 - 10);
100122

101-
*(u16 *)location = (*(u16 *)location & 0xe003) |
102-
imm11 | imm10 | imm9_8 | imm7 | imm6 | imm5 | imm4 | imm3_1;
103-
return 0;
123+
return riscv_insn_rvc_rmw(location, 0xe003,
124+
imm11 | imm10 | imm9_8 | imm7 | imm6 | imm5 | imm4 | imm3_1);
104125
}
105126

106-
static int apply_r_riscv_pcrel_hi20_rela(struct module *me, u32 *location,
127+
static int apply_r_riscv_pcrel_hi20_rela(struct module *me, void *location,
107128
Elf_Addr v)
108129
{
109-
ptrdiff_t offset = (void *)v - (void *)location;
110-
s32 hi20;
130+
ptrdiff_t offset = (void *)v - location;
111131

112132
if (!riscv_insn_valid_32bit_offset(offset)) {
113133
pr_err(
@@ -116,23 +136,20 @@ static int apply_r_riscv_pcrel_hi20_rela(struct module *me, u32 *location,
116136
return -EINVAL;
117137
}
118138

119-
hi20 = (offset + 0x800) & 0xfffff000;
120-
*location = (*location & 0xfff) | hi20;
121-
return 0;
139+
return riscv_insn_rmw(location, 0xfff, (offset + 0x800) & 0xfffff000);
122140
}
123141

124-
static int apply_r_riscv_pcrel_lo12_i_rela(struct module *me, u32 *location,
142+
static int apply_r_riscv_pcrel_lo12_i_rela(struct module *me, void *location,
125143
Elf_Addr v)
126144
{
127145
/*
128146
* v is the lo12 value to fill. It is calculated before calling this
129147
* handler.
130148
*/
131-
*location = (*location & 0xfffff) | ((v & 0xfff) << 20);
132-
return 0;
149+
return riscv_insn_rmw(location, 0xfffff, (v & 0xfff) << 20);
133150
}
134151

135-
static int apply_r_riscv_pcrel_lo12_s_rela(struct module *me, u32 *location,
152+
static int apply_r_riscv_pcrel_lo12_s_rela(struct module *me, void *location,
136153
Elf_Addr v)
137154
{
138155
/*
@@ -142,82 +159,72 @@ static int apply_r_riscv_pcrel_lo12_s_rela(struct module *me, u32 *location,
142159
u32 imm11_5 = (v & 0xfe0) << (31 - 11);
143160
u32 imm4_0 = (v & 0x1f) << (11 - 4);
144161

145-
*location = (*location & 0x1fff07f) | imm11_5 | imm4_0;
146-
return 0;
162+
return riscv_insn_rmw(location, 0x1fff07f, imm11_5 | imm4_0);
147163
}
148164

149-
static int apply_r_riscv_hi20_rela(struct module *me, u32 *location,
165+
static int apply_r_riscv_hi20_rela(struct module *me, void *location,
150166
Elf_Addr v)
151167
{
152-
s32 hi20;
153-
154168
if (IS_ENABLED(CONFIG_CMODEL_MEDLOW)) {
155169
pr_err(
156170
"%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
157171
me->name, (long long)v, location);
158172
return -EINVAL;
159173
}
160174

161-
hi20 = ((s32)v + 0x800) & 0xfffff000;
162-
*location = (*location & 0xfff) | hi20;
163-
return 0;
175+
return riscv_insn_rmw(location, 0xfff, ((s32)v + 0x800) & 0xfffff000);
164176
}
165177

166-
static int apply_r_riscv_lo12_i_rela(struct module *me, u32 *location,
178+
static int apply_r_riscv_lo12_i_rela(struct module *me, void *location,
167179
Elf_Addr v)
168180
{
169181
/* Skip medlow checking because of filtering by HI20 already */
170182
s32 hi20 = ((s32)v + 0x800) & 0xfffff000;
171183
s32 lo12 = ((s32)v - hi20);
172-
*location = (*location & 0xfffff) | ((lo12 & 0xfff) << 20);
173-
return 0;
184+
185+
return riscv_insn_rmw(location, 0xfffff, (lo12 & 0xfff) << 20);
174186
}
175187

176-
static int apply_r_riscv_lo12_s_rela(struct module *me, u32 *location,
188+
static int apply_r_riscv_lo12_s_rela(struct module *me, void *location,
177189
Elf_Addr v)
178190
{
179191
/* Skip medlow checking because of filtering by HI20 already */
180192
s32 hi20 = ((s32)v + 0x800) & 0xfffff000;
181193
s32 lo12 = ((s32)v - hi20);
182194
u32 imm11_5 = (lo12 & 0xfe0) << (31 - 11);
183195
u32 imm4_0 = (lo12 & 0x1f) << (11 - 4);
184-
*location = (*location & 0x1fff07f) | imm11_5 | imm4_0;
185-
return 0;
196+
197+
return riscv_insn_rmw(location, 0x1fff07f, imm11_5 | imm4_0);
186198
}
187199

188-
static int apply_r_riscv_got_hi20_rela(struct module *me, u32 *location,
200+
static int apply_r_riscv_got_hi20_rela(struct module *me, void *location,
189201
Elf_Addr v)
190202
{
191-
ptrdiff_t offset = (void *)v - (void *)location;
192-
s32 hi20;
203+
ptrdiff_t offset = (void *)v - location;
193204

194205
/* Always emit the got entry */
195206
if (IS_ENABLED(CONFIG_MODULE_SECTIONS)) {
196-
offset = module_emit_got_entry(me, v);
197-
offset = (void *)offset - (void *)location;
207+
offset = (void *)module_emit_got_entry(me, v) - location;
198208
} else {
199209
pr_err(
200210
"%s: can not generate the GOT entry for symbol = %016llx from PC = %p\n",
201211
me->name, (long long)v, location);
202212
return -EINVAL;
203213
}
204214

205-
hi20 = (offset + 0x800) & 0xfffff000;
206-
*location = (*location & 0xfff) | hi20;
207-
return 0;
215+
return riscv_insn_rmw(location, 0xfff, (offset + 0x800) & 0xfffff000);
208216
}
209217

210-
static int apply_r_riscv_call_plt_rela(struct module *me, u32 *location,
218+
static int apply_r_riscv_call_plt_rela(struct module *me, void *location,
211219
Elf_Addr v)
212220
{
213-
ptrdiff_t offset = (void *)v - (void *)location;
221+
ptrdiff_t offset = (void *)v - location;
214222
u32 hi20, lo12;
215223

216224
if (!riscv_insn_valid_32bit_offset(offset)) {
217225
/* Only emit the plt entry if offset over 32-bit range */
218226
if (IS_ENABLED(CONFIG_MODULE_SECTIONS)) {
219-
offset = module_emit_plt_entry(me, v);
220-
offset = (void *)offset - (void *)location;
227+
offset = (void *)module_emit_plt_entry(me, v) - location;
221228
} else {
222229
pr_err(
223230
"%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
@@ -228,15 +235,14 @@ static int apply_r_riscv_call_plt_rela(struct module *me, u32 *location,
228235

229236
hi20 = (offset + 0x800) & 0xfffff000;
230237
lo12 = (offset - hi20) & 0xfff;
231-
*location = (*location & 0xfff) | hi20;
232-
*(location + 1) = (*(location + 1) & 0xfffff) | (lo12 << 20);
233-
return 0;
238+
riscv_insn_rmw(location, 0xfff, hi20);
239+
return riscv_insn_rmw(location + 4, 0xfffff, lo12 << 20);
234240
}
235241

236-
static int apply_r_riscv_call_rela(struct module *me, u32 *location,
242+
static int apply_r_riscv_call_rela(struct module *me, void *location,
237243
Elf_Addr v)
238244
{
239-
ptrdiff_t offset = (void *)v - (void *)location;
245+
ptrdiff_t offset = (void *)v - location;
240246
u32 hi20, lo12;
241247

242248
if (!riscv_insn_valid_32bit_offset(offset)) {
@@ -248,18 +254,17 @@ static int apply_r_riscv_call_rela(struct module *me, u32 *location,
248254

249255
hi20 = (offset + 0x800) & 0xfffff000;
250256
lo12 = (offset - hi20) & 0xfff;
251-
*location = (*location & 0xfff) | hi20;
252-
*(location + 1) = (*(location + 1) & 0xfffff) | (lo12 << 20);
253-
return 0;
257+
riscv_insn_rmw(location, 0xfff, hi20);
258+
return riscv_insn_rmw(location + 4, 0xfffff, lo12 << 20);
254259
}
255260

256-
static int apply_r_riscv_relax_rela(struct module *me, u32 *location,
261+
static int apply_r_riscv_relax_rela(struct module *me, void *location,
257262
Elf_Addr v)
258263
{
259264
return 0;
260265
}
261266

262-
static int apply_r_riscv_align_rela(struct module *me, u32 *location,
267+
static int apply_r_riscv_align_rela(struct module *me, void *location,
263268
Elf_Addr v)
264269
{
265270
pr_err(
@@ -268,49 +273,49 @@ static int apply_r_riscv_align_rela(struct module *me, u32 *location,
268273
return -EINVAL;
269274
}
270275

271-
static int apply_r_riscv_add16_rela(struct module *me, u32 *location,
276+
static int apply_r_riscv_add16_rela(struct module *me, void *location,
272277
Elf_Addr v)
273278
{
274279
*(u16 *)location += (u16)v;
275280
return 0;
276281
}
277282

278-
static int apply_r_riscv_add32_rela(struct module *me, u32 *location,
283+
static int apply_r_riscv_add32_rela(struct module *me, void *location,
279284
Elf_Addr v)
280285
{
281286
*(u32 *)location += (u32)v;
282287
return 0;
283288
}
284289

285-
static int apply_r_riscv_add64_rela(struct module *me, u32 *location,
290+
static int apply_r_riscv_add64_rela(struct module *me, void *location,
286291
Elf_Addr v)
287292
{
288293
*(u64 *)location += (u64)v;
289294
return 0;
290295
}
291296

292-
static int apply_r_riscv_sub16_rela(struct module *me, u32 *location,
297+
static int apply_r_riscv_sub16_rela(struct module *me, void *location,
293298
Elf_Addr v)
294299
{
295300
*(u16 *)location -= (u16)v;
296301
return 0;
297302
}
298303

299-
static int apply_r_riscv_sub32_rela(struct module *me, u32 *location,
304+
static int apply_r_riscv_sub32_rela(struct module *me, void *location,
300305
Elf_Addr v)
301306
{
302307
*(u32 *)location -= (u32)v;
303308
return 0;
304309
}
305310

306-
static int apply_r_riscv_sub64_rela(struct module *me, u32 *location,
311+
static int apply_r_riscv_sub64_rela(struct module *me, void *location,
307312
Elf_Addr v)
308313
{
309314
*(u64 *)location -= (u64)v;
310315
return 0;
311316
}
312317

313-
static int (*reloc_handlers_rela[]) (struct module *me, u32 *location,
318+
static int (*reloc_handlers_rela[]) (struct module *me, void *location,
314319
Elf_Addr v) = {
315320
[R_RISCV_32] = apply_r_riscv_32_rela,
316321
[R_RISCV_64] = apply_r_riscv_64_rela,
@@ -342,9 +347,9 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
342347
struct module *me)
343348
{
344349
Elf_Rela *rel = (void *) sechdrs[relsec].sh_addr;
345-
int (*handler)(struct module *me, u32 *location, Elf_Addr v);
350+
int (*handler)(struct module *me, void *location, Elf_Addr v);
346351
Elf_Sym *sym;
347-
u32 *location;
352+
void *location;
348353
unsigned int i, type;
349354
Elf_Addr v;
350355
int res;

0 commit comments

Comments
 (0)