23
23
#include <asm/insn.h>
24
24
#include <asm/scs.h>
25
25
#include <asm/sections.h>
26
+ #include <asm/text-patching.h>
26
27
27
28
enum aarch64_reloc_op {
28
29
RELOC_OP_NONE ,
@@ -48,7 +49,17 @@ static u64 do_reloc(enum aarch64_reloc_op reloc_op, __le32 *place, u64 val)
48
49
return 0 ;
49
50
}
50
51
51
- static int reloc_data (enum aarch64_reloc_op op , void * place , u64 val , int len )
52
+ #define WRITE_PLACE (place , val , mod ) do { \
53
+ __typeof__(val) __val = (val); \
54
+ \
55
+ if (mod->state == MODULE_STATE_UNFORMED) \
56
+ *(place) = __val; \
57
+ else \
58
+ aarch64_insn_copy(place, &(__val), sizeof(*place)); \
59
+ } while (0)
60
+
61
+ static int reloc_data (enum aarch64_reloc_op op , void * place , u64 val , int len ,
62
+ struct module * me )
52
63
{
53
64
s64 sval = do_reloc (op , place , val );
54
65
@@ -66,7 +77,7 @@ static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len)
66
77
67
78
switch (len ) {
68
79
case 16 :
69
- * ( s16 * )place = sval ;
80
+ WRITE_PLACE (( s16 * )place , sval , me ) ;
70
81
switch (op ) {
71
82
case RELOC_OP_ABS :
72
83
if (sval < 0 || sval > U16_MAX )
@@ -82,7 +93,7 @@ static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len)
82
93
}
83
94
break ;
84
95
case 32 :
85
- * ( s32 * )place = sval ;
96
+ WRITE_PLACE (( s32 * )place , sval , me ) ;
86
97
switch (op ) {
87
98
case RELOC_OP_ABS :
88
99
if (sval < 0 || sval > U32_MAX )
@@ -98,7 +109,7 @@ static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len)
98
109
}
99
110
break ;
100
111
case 64 :
101
- * ( s64 * )place = sval ;
112
+ WRITE_PLACE (( s64 * )place , sval , me ) ;
102
113
break ;
103
114
default :
104
115
pr_err ("Invalid length (%d) for data relocation\n" , len );
@@ -113,7 +124,8 @@ enum aarch64_insn_movw_imm_type {
113
124
};
114
125
115
126
static int reloc_insn_movw (enum aarch64_reloc_op op , __le32 * place , u64 val ,
116
- int lsb , enum aarch64_insn_movw_imm_type imm_type )
127
+ int lsb , enum aarch64_insn_movw_imm_type imm_type ,
128
+ struct module * me )
117
129
{
118
130
u64 imm ;
119
131
s64 sval ;
@@ -145,7 +157,7 @@ static int reloc_insn_movw(enum aarch64_reloc_op op, __le32 *place, u64 val,
145
157
146
158
/* Update the instruction with the new encoding. */
147
159
insn = aarch64_insn_encode_immediate (AARCH64_INSN_IMM_16 , insn , imm );
148
- * place = cpu_to_le32 (insn );
160
+ WRITE_PLACE ( place , cpu_to_le32 (insn ), me );
149
161
150
162
if (imm > U16_MAX )
151
163
return - ERANGE ;
@@ -154,7 +166,8 @@ static int reloc_insn_movw(enum aarch64_reloc_op op, __le32 *place, u64 val,
154
166
}
155
167
156
168
static int reloc_insn_imm (enum aarch64_reloc_op op , __le32 * place , u64 val ,
157
- int lsb , int len , enum aarch64_insn_imm_type imm_type )
169
+ int lsb , int len , enum aarch64_insn_imm_type imm_type ,
170
+ struct module * me )
158
171
{
159
172
u64 imm , imm_mask ;
160
173
s64 sval ;
@@ -170,7 +183,7 @@ static int reloc_insn_imm(enum aarch64_reloc_op op, __le32 *place, u64 val,
170
183
171
184
/* Update the instruction's immediate field. */
172
185
insn = aarch64_insn_encode_immediate (imm_type , insn , imm );
173
- * place = cpu_to_le32 (insn );
186
+ WRITE_PLACE ( place , cpu_to_le32 (insn ), me );
174
187
175
188
/*
176
189
* Extract the upper value bits (including the sign bit) and
@@ -189,17 +202,17 @@ static int reloc_insn_imm(enum aarch64_reloc_op op, __le32 *place, u64 val,
189
202
}
190
203
191
204
static int reloc_insn_adrp (struct module * mod , Elf64_Shdr * sechdrs ,
192
- __le32 * place , u64 val )
205
+ __le32 * place , u64 val , struct module * me )
193
206
{
194
207
u32 insn ;
195
208
196
209
if (!is_forbidden_offset_for_adrp (place ))
197
210
return reloc_insn_imm (RELOC_OP_PAGE , place , val , 12 , 21 ,
198
- AARCH64_INSN_IMM_ADR );
211
+ AARCH64_INSN_IMM_ADR , me );
199
212
200
213
/* patch ADRP to ADR if it is in range */
201
214
if (!reloc_insn_imm (RELOC_OP_PREL , place , val & ~0xfff , 0 , 21 ,
202
- AARCH64_INSN_IMM_ADR )) {
215
+ AARCH64_INSN_IMM_ADR , me )) {
203
216
insn = le32_to_cpu (* place );
204
217
insn &= ~BIT (31 );
205
218
} else {
@@ -211,7 +224,7 @@ static int reloc_insn_adrp(struct module *mod, Elf64_Shdr *sechdrs,
211
224
AARCH64_INSN_BRANCH_NOLINK );
212
225
}
213
226
214
- * place = cpu_to_le32 (insn );
227
+ WRITE_PLACE ( place , cpu_to_le32 (insn ), me );
215
228
return 0 ;
216
229
}
217
230
@@ -255,23 +268,23 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
255
268
/* Data relocations. */
256
269
case R_AARCH64_ABS64 :
257
270
overflow_check = false;
258
- ovf = reloc_data (RELOC_OP_ABS , loc , val , 64 );
271
+ ovf = reloc_data (RELOC_OP_ABS , loc , val , 64 , me );
259
272
break ;
260
273
case R_AARCH64_ABS32 :
261
- ovf = reloc_data (RELOC_OP_ABS , loc , val , 32 );
274
+ ovf = reloc_data (RELOC_OP_ABS , loc , val , 32 , me );
262
275
break ;
263
276
case R_AARCH64_ABS16 :
264
- ovf = reloc_data (RELOC_OP_ABS , loc , val , 16 );
277
+ ovf = reloc_data (RELOC_OP_ABS , loc , val , 16 , me );
265
278
break ;
266
279
case R_AARCH64_PREL64 :
267
280
overflow_check = false;
268
- ovf = reloc_data (RELOC_OP_PREL , loc , val , 64 );
281
+ ovf = reloc_data (RELOC_OP_PREL , loc , val , 64 , me );
269
282
break ;
270
283
case R_AARCH64_PREL32 :
271
- ovf = reloc_data (RELOC_OP_PREL , loc , val , 32 );
284
+ ovf = reloc_data (RELOC_OP_PREL , loc , val , 32 , me );
272
285
break ;
273
286
case R_AARCH64_PREL16 :
274
- ovf = reloc_data (RELOC_OP_PREL , loc , val , 16 );
287
+ ovf = reloc_data (RELOC_OP_PREL , loc , val , 16 , me );
275
288
break ;
276
289
277
290
/* MOVW instruction relocations. */
@@ -280,135 +293,135 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
280
293
fallthrough ;
281
294
case R_AARCH64_MOVW_UABS_G0 :
282
295
ovf = reloc_insn_movw (RELOC_OP_ABS , loc , val , 0 ,
283
- AARCH64_INSN_IMM_MOVKZ );
296
+ AARCH64_INSN_IMM_MOVKZ , me );
284
297
break ;
285
298
case R_AARCH64_MOVW_UABS_G1_NC :
286
299
overflow_check = false;
287
300
fallthrough ;
288
301
case R_AARCH64_MOVW_UABS_G1 :
289
302
ovf = reloc_insn_movw (RELOC_OP_ABS , loc , val , 16 ,
290
- AARCH64_INSN_IMM_MOVKZ );
303
+ AARCH64_INSN_IMM_MOVKZ , me );
291
304
break ;
292
305
case R_AARCH64_MOVW_UABS_G2_NC :
293
306
overflow_check = false;
294
307
fallthrough ;
295
308
case R_AARCH64_MOVW_UABS_G2 :
296
309
ovf = reloc_insn_movw (RELOC_OP_ABS , loc , val , 32 ,
297
- AARCH64_INSN_IMM_MOVKZ );
310
+ AARCH64_INSN_IMM_MOVKZ , me );
298
311
break ;
299
312
case R_AARCH64_MOVW_UABS_G3 :
300
313
/* We're using the top bits so we can't overflow. */
301
314
overflow_check = false;
302
315
ovf = reloc_insn_movw (RELOC_OP_ABS , loc , val , 48 ,
303
- AARCH64_INSN_IMM_MOVKZ );
316
+ AARCH64_INSN_IMM_MOVKZ , me );
304
317
break ;
305
318
case R_AARCH64_MOVW_SABS_G0 :
306
319
ovf = reloc_insn_movw (RELOC_OP_ABS , loc , val , 0 ,
307
- AARCH64_INSN_IMM_MOVNZ );
320
+ AARCH64_INSN_IMM_MOVNZ , me );
308
321
break ;
309
322
case R_AARCH64_MOVW_SABS_G1 :
310
323
ovf = reloc_insn_movw (RELOC_OP_ABS , loc , val , 16 ,
311
- AARCH64_INSN_IMM_MOVNZ );
324
+ AARCH64_INSN_IMM_MOVNZ , me );
312
325
break ;
313
326
case R_AARCH64_MOVW_SABS_G2 :
314
327
ovf = reloc_insn_movw (RELOC_OP_ABS , loc , val , 32 ,
315
- AARCH64_INSN_IMM_MOVNZ );
328
+ AARCH64_INSN_IMM_MOVNZ , me );
316
329
break ;
317
330
case R_AARCH64_MOVW_PREL_G0_NC :
318
331
overflow_check = false;
319
332
ovf = reloc_insn_movw (RELOC_OP_PREL , loc , val , 0 ,
320
- AARCH64_INSN_IMM_MOVKZ );
333
+ AARCH64_INSN_IMM_MOVKZ , me );
321
334
break ;
322
335
case R_AARCH64_MOVW_PREL_G0 :
323
336
ovf = reloc_insn_movw (RELOC_OP_PREL , loc , val , 0 ,
324
- AARCH64_INSN_IMM_MOVNZ );
337
+ AARCH64_INSN_IMM_MOVNZ , me );
325
338
break ;
326
339
case R_AARCH64_MOVW_PREL_G1_NC :
327
340
overflow_check = false;
328
341
ovf = reloc_insn_movw (RELOC_OP_PREL , loc , val , 16 ,
329
- AARCH64_INSN_IMM_MOVKZ );
342
+ AARCH64_INSN_IMM_MOVKZ , me );
330
343
break ;
331
344
case R_AARCH64_MOVW_PREL_G1 :
332
345
ovf = reloc_insn_movw (RELOC_OP_PREL , loc , val , 16 ,
333
- AARCH64_INSN_IMM_MOVNZ );
346
+ AARCH64_INSN_IMM_MOVNZ , me );
334
347
break ;
335
348
case R_AARCH64_MOVW_PREL_G2_NC :
336
349
overflow_check = false;
337
350
ovf = reloc_insn_movw (RELOC_OP_PREL , loc , val , 32 ,
338
- AARCH64_INSN_IMM_MOVKZ );
351
+ AARCH64_INSN_IMM_MOVKZ , me );
339
352
break ;
340
353
case R_AARCH64_MOVW_PREL_G2 :
341
354
ovf = reloc_insn_movw (RELOC_OP_PREL , loc , val , 32 ,
342
- AARCH64_INSN_IMM_MOVNZ );
355
+ AARCH64_INSN_IMM_MOVNZ , me );
343
356
break ;
344
357
case R_AARCH64_MOVW_PREL_G3 :
345
358
/* We're using the top bits so we can't overflow. */
346
359
overflow_check = false;
347
360
ovf = reloc_insn_movw (RELOC_OP_PREL , loc , val , 48 ,
348
- AARCH64_INSN_IMM_MOVNZ );
361
+ AARCH64_INSN_IMM_MOVNZ , me );
349
362
break ;
350
363
351
364
/* Immediate instruction relocations. */
352
365
case R_AARCH64_LD_PREL_LO19 :
353
366
ovf = reloc_insn_imm (RELOC_OP_PREL , loc , val , 2 , 19 ,
354
- AARCH64_INSN_IMM_19 );
367
+ AARCH64_INSN_IMM_19 , me );
355
368
break ;
356
369
case R_AARCH64_ADR_PREL_LO21 :
357
370
ovf = reloc_insn_imm (RELOC_OP_PREL , loc , val , 0 , 21 ,
358
- AARCH64_INSN_IMM_ADR );
371
+ AARCH64_INSN_IMM_ADR , me );
359
372
break ;
360
373
case R_AARCH64_ADR_PREL_PG_HI21_NC :
361
374
overflow_check = false;
362
375
fallthrough ;
363
376
case R_AARCH64_ADR_PREL_PG_HI21 :
364
- ovf = reloc_insn_adrp (me , sechdrs , loc , val );
377
+ ovf = reloc_insn_adrp (me , sechdrs , loc , val , me );
365
378
if (ovf && ovf != - ERANGE )
366
379
return ovf ;
367
380
break ;
368
381
case R_AARCH64_ADD_ABS_LO12_NC :
369
382
case R_AARCH64_LDST8_ABS_LO12_NC :
370
383
overflow_check = false;
371
384
ovf = reloc_insn_imm (RELOC_OP_ABS , loc , val , 0 , 12 ,
372
- AARCH64_INSN_IMM_12 );
385
+ AARCH64_INSN_IMM_12 , me );
373
386
break ;
374
387
case R_AARCH64_LDST16_ABS_LO12_NC :
375
388
overflow_check = false;
376
389
ovf = reloc_insn_imm (RELOC_OP_ABS , loc , val , 1 , 11 ,
377
- AARCH64_INSN_IMM_12 );
390
+ AARCH64_INSN_IMM_12 , me );
378
391
break ;
379
392
case R_AARCH64_LDST32_ABS_LO12_NC :
380
393
overflow_check = false;
381
394
ovf = reloc_insn_imm (RELOC_OP_ABS , loc , val , 2 , 10 ,
382
- AARCH64_INSN_IMM_12 );
395
+ AARCH64_INSN_IMM_12 , me );
383
396
break ;
384
397
case R_AARCH64_LDST64_ABS_LO12_NC :
385
398
overflow_check = false;
386
399
ovf = reloc_insn_imm (RELOC_OP_ABS , loc , val , 3 , 9 ,
387
- AARCH64_INSN_IMM_12 );
400
+ AARCH64_INSN_IMM_12 , me );
388
401
break ;
389
402
case R_AARCH64_LDST128_ABS_LO12_NC :
390
403
overflow_check = false;
391
404
ovf = reloc_insn_imm (RELOC_OP_ABS , loc , val , 4 , 8 ,
392
- AARCH64_INSN_IMM_12 );
405
+ AARCH64_INSN_IMM_12 , me );
393
406
break ;
394
407
case R_AARCH64_TSTBR14 :
395
408
ovf = reloc_insn_imm (RELOC_OP_PREL , loc , val , 2 , 14 ,
396
- AARCH64_INSN_IMM_14 );
409
+ AARCH64_INSN_IMM_14 , me );
397
410
break ;
398
411
case R_AARCH64_CONDBR19 :
399
412
ovf = reloc_insn_imm (RELOC_OP_PREL , loc , val , 2 , 19 ,
400
- AARCH64_INSN_IMM_19 );
413
+ AARCH64_INSN_IMM_19 , me );
401
414
break ;
402
415
case R_AARCH64_JUMP26 :
403
416
case R_AARCH64_CALL26 :
404
417
ovf = reloc_insn_imm (RELOC_OP_PREL , loc , val , 2 , 26 ,
405
- AARCH64_INSN_IMM_26 );
418
+ AARCH64_INSN_IMM_26 , me );
406
419
if (ovf == - ERANGE ) {
407
420
val = module_emit_plt_entry (me , sechdrs , loc , & rel [i ], sym );
408
421
if (!val )
409
422
return - ENOEXEC ;
410
423
ovf = reloc_insn_imm (RELOC_OP_PREL , loc , val , 2 ,
411
- 26 , AARCH64_INSN_IMM_26 );
424
+ 26 , AARCH64_INSN_IMM_26 , me );
412
425
}
413
426
break ;
414
427
0 commit comments