From 7549d1f31a4d7476c795c92e5e6478c98bb2539c Mon Sep 17 00:00:00 2001
From: Chris Johns <chrisj@rtems.org>
Date: Thu, 10 Sep 2020 15:04:24 +1000
Subject: [PATCH v2] libdl/riscv: Fix RISCV issues with libdl tests
- Support misaligned read and write accesses
- Add a RISCV reloc trace
- Add a better check for a valid symbol name. An empty name is
considered invalid and should not be added to an object files
list of unresolved symbols.
Updates #4069
---
cpukit/include/rtems/rtl/rtl-sym.h | 9 ++
cpukit/libdl/rtl-elf.c | 27 +++--
cpukit/libdl/rtl-mdreloc-riscv.c | 163 +++++++++++++++++++++++++----
cpukit/libdl/rtl-sym.c | 13 +++
cpukit/libdl/rtl-unresolved.c | 9 +-
5 files changed, 187 insertions(+), 34 deletions(-)
diff --git a/cpukit/include/rtems/rtl/rtl-sym.h b/cpukit/include/rtems/rtl/rtl-sym.h
index 07cad4cab6..838c1d2b3a 100644
a
|
b
|
void rtems_rtl_symbol_obj_erase_local (rtems_rtl_obj* obj); |
137 | 137 | */ |
138 | 138 | void rtems_rtl_symbol_obj_erase (rtems_rtl_obj* obj); |
139 | 139 | |
| 140 | /** |
| 141 | * Is the symbol name valid? A valid symbol name must exist, i.e. not |
| 142 | * NULL and the string has a length greater than 0. |
| 143 | * |
| 144 | * @param name Symbol name string. |
| 145 | * @retval bool Return true if there is a valid symbol name. |
| 146 | */ |
| 147 | bool rtems_rtl_symbol_name_valid (const char* name); |
| 148 | |
140 | 149 | #ifdef __cplusplus |
141 | 150 | } |
142 | 151 | #endif /* __cplusplus */ |
diff --git a/cpukit/libdl/rtl-elf.c b/cpukit/libdl/rtl-elf.c
index 75b3d9c953..2f2c4c7792 100644
a
|
b
|
|
28 | 28 | #include <unistd.h> |
29 | 29 | |
30 | 30 | #include <rtems/rtl/rtl.h> |
| 31 | #include <rtems/rtl/rtl-trace.h> |
| 32 | #include <rtems/rtl/rtl-unresolved.h> |
| 33 | |
31 | 34 | #include "rtl-elf.h" |
32 | 35 | #include "rtl-error.h" |
33 | | #include <rtems/rtl/rtl-trace.h> |
34 | 36 | #include "rtl-trampoline.h" |
35 | 37 | #include "rtl-unwind.h" |
36 | | #include <rtems/rtl/rtl-unresolved.h> |
37 | 38 | |
38 | 39 | /** |
39 | 40 | * The offsets in the reloc words. |
… |
… |
rtems_rtl_elf_reloc_parser (rtems_rtl_obj* obj, |
276 | 277 | /* |
277 | 278 | * Handle any dependencies if there is a valid symbol. |
278 | 279 | */ |
279 | | if (symname != NULL) |
| 280 | if (rtems_rtl_symbol_name_valid (symname)) |
280 | 281 | { |
281 | 282 | /* |
282 | 283 | * Find the symbol's object file. It cannot be NULL so ignore that result |
… |
… |
rtems_rtl_elf_reloc_relocator (rtems_rtl_obj* obj, |
335 | 336 | rel_words[REL_R_ADDEND] = 0; |
336 | 337 | } |
337 | 338 | |
338 | | if (!rtems_rtl_unresolved_add (obj, |
339 | | flags, |
340 | | symname, |
341 | | targetsect->section, |
342 | | rel_words)) |
343 | | return false; |
| 339 | if (rtems_rtl_symbol_name_valid (symname)) |
| 340 | { |
| 341 | if (!rtems_rtl_unresolved_add (obj, |
| 342 | flags, |
| 343 | symname, |
| 344 | targetsect->section, |
| 345 | rel_words)) |
| 346 | return false; |
344 | 347 | |
345 | | ++obj->unresolved; |
| 348 | ++obj->unresolved; |
| 349 | } |
346 | 350 | } |
347 | 351 | else |
348 | 352 | { |
… |
… |
rtems_rtl_elf_parse_sections (rtems_rtl_obj* obj, int fd, Elf_Ehdr* ehdr) |
1434 | 1438 | if (rtems_rtl_obj_aname_valid (obj)) |
1435 | 1439 | { |
1436 | 1440 | const char* symname = rtems_rtl_elf_separated_section (name); |
1437 | | if (symname != NULL && rtems_rtl_symbol_global_find (symname)) |
| 1441 | if (rtems_rtl_symbol_name_valid (symname) && |
| 1442 | rtems_rtl_symbol_global_find (symname)) |
1438 | 1443 | flags &= ~RTEMS_RTL_OBJ_SECT_LOAD; |
1439 | 1444 | } |
1440 | 1445 | |
diff --git a/cpukit/libdl/rtl-mdreloc-riscv.c b/cpukit/libdl/rtl-mdreloc-riscv.c
index e6778dcc90..688876b013 100644
a
|
b
|
|
38 | 38 | #include <sys/cdefs.h> |
39 | 39 | |
40 | 40 | #include <errno.h> |
| 41 | #include <inttypes.h> |
41 | 42 | #include <stdio.h> |
42 | 43 | #include <sys/types.h> |
43 | 44 | #include <sys/stat.h> |
… |
… |
rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj* obj, |
113 | 114 | return rtems_rtl_elf_rel_no_error; |
114 | 115 | } |
115 | 116 | |
| 117 | static const char* reloc_label(unsigned int r_type) |
| 118 | { |
| 119 | const char* what = NULL; |
| 120 | switch (r_type) { |
| 121 | case R_TYPE(NONE): |
| 122 | what = "NONE"; |
| 123 | break; |
| 124 | case R_TYPE(RVC_BRANCH): |
| 125 | what = "RVC_BRANCH"; |
| 126 | break; |
| 127 | case R_TYPE(RVC_JUMP): |
| 128 | what = "RVC_JUMP"; |
| 129 | break; |
| 130 | case R_TYPE(RVC_LUI): |
| 131 | what = "RVC_LUI"; |
| 132 | break; |
| 133 | case R_TYPE(JAL): |
| 134 | what = "JAL"; |
| 135 | break; |
| 136 | case R_TYPE(BRANCH): |
| 137 | what = "BRANCH"; |
| 138 | break; |
| 139 | case R_TYPE(64): |
| 140 | what = "64"; |
| 141 | break; |
| 142 | case R_TYPE(32): |
| 143 | what = "32"; |
| 144 | break; |
| 145 | case R_TYPE(SET6): |
| 146 | what = "SET6"; |
| 147 | break; |
| 148 | case R_TYPE(SET8): |
| 149 | what = "SET8"; |
| 150 | break; |
| 151 | case R_TYPE(SET16): |
| 152 | what = "SET16"; |
| 153 | break; |
| 154 | case R_TYPE(SET32): |
| 155 | what = "SET32"; |
| 156 | break; |
| 157 | case R_TYPE(ADD8): |
| 158 | what = "ADD8"; |
| 159 | break; |
| 160 | case R_TYPE(ADD16): |
| 161 | what = "ADD16"; |
| 162 | break; |
| 163 | case R_TYPE(ADD32): |
| 164 | what = "ADD32"; |
| 165 | break; |
| 166 | case R_TYPE(ADD64): |
| 167 | what = "ADD64"; |
| 168 | break; |
| 169 | case R_TYPE(SUB6): |
| 170 | what = "SUB6"; |
| 171 | break; |
| 172 | case R_TYPE(SUB8): |
| 173 | what = "SUB8"; |
| 174 | break; |
| 175 | case R_TYPE(SUB16): |
| 176 | what = "SUB16"; |
| 177 | break; |
| 178 | case R_TYPE(SUB32): |
| 179 | what = "SUB32"; |
| 180 | break; |
| 181 | case R_TYPE(SUB64): |
| 182 | what = "SUB64"; |
| 183 | break; |
| 184 | case R_TYPE(32_PCREL): |
| 185 | what = "32_PCREL"; |
| 186 | break; |
| 187 | case R_TYPE(PCREL_HI20): |
| 188 | what = "PCREL_HI20"; |
| 189 | break; |
| 190 | case R_TYPE(GOT_HI20): |
| 191 | case R_TYPE(HI20): |
| 192 | what = "HI20"; |
| 193 | break; |
| 194 | case R_TYPE(PCREL_LO12_I): |
| 195 | what = "PCREL_LO12_I"; |
| 196 | break; |
| 197 | case R_TYPE(LO12_I): |
| 198 | what = "LO12_I"; |
| 199 | break; |
| 200 | case R_TYPE(PCREL_LO12_S): |
| 201 | what = "PCREL_LO12_S"; |
| 202 | break; |
| 203 | case R_TYPE(LO12_S): |
| 204 | what = "LO12_S"; |
| 205 | break; |
| 206 | case R_TYPE(CALL_PLT): |
| 207 | case R_TYPE(CALL): |
| 208 | what = "CALL"; |
| 209 | break; |
| 210 | default: |
| 211 | break; |
| 212 | } |
| 213 | return what; |
| 214 | } |
| 215 | |
116 | 216 | // Extract bits V[Begin:End], where range is inclusive, and Begin must be < 63. |
117 | 217 | static uint32_t extractBits(uint64_t v, uint32_t begin, uint32_t end) { |
118 | 218 | return (v & ((1ULL << (begin + 1)) - 1)) >> end; |
… |
… |
static int64_t SignExtend64(uint64_t val, unsigned bits) { |
122 | 222 | return (int64_t )(((int64_t) (val << (64 - bits))) >> (64 - bits)); |
123 | 223 | } |
124 | 224 | |
| 225 | static void write8le(void *loc, uint8_t val) { |
| 226 | *((uint8_t *) loc) = val; |
| 227 | } |
| 228 | |
125 | 229 | static void write16le(void *loc, uint16_t val) { |
126 | 230 | *((uint16_t *) loc) = val; |
127 | 231 | } |
128 | 232 | |
129 | 233 | static void write32le(void *loc, uint32_t val) { |
130 | | *((uint32_t *) loc) = val; |
| 234 | if ((((intptr_t) loc) & 3) == 0) |
| 235 | *((uint32_t *) loc) = val; |
| 236 | else { |
| 237 | write8le(loc, val >> 24); |
| 238 | write8le(loc + 1, val >> 16); |
| 239 | write8le(loc + 2, val >> 8); |
| 240 | write8le(loc + 3, val); |
| 241 | } |
131 | 242 | } |
132 | 243 | |
133 | 244 | static void write64le(void *loc, uint64_t val) { |
134 | 245 | *((uint64_t *) loc) = val; |
135 | 246 | } |
136 | 247 | |
| 248 | static uint8_t read8le(void *loc) { |
| 249 | return *((uint8_t *) loc); |
| 250 | } |
| 251 | |
137 | 252 | static uint16_t read16le(void *loc) { |
138 | 253 | return *((uint16_t *) loc); |
139 | 254 | } |
140 | 255 | |
141 | 256 | static uint32_t read32le(void *loc) { |
142 | | return *((uint32_t *) loc); |
| 257 | if ((((intptr_t) loc) & 3) == 0) |
| 258 | return *((uint32_t *) loc); |
| 259 | return (read8le(loc) << 24) | (read8le(loc + 1) << 16) | (read8le(loc + 2) << 8) | read8le(loc + 3); |
143 | 260 | } |
144 | 261 | |
145 | 262 | static uint64_t read64le(void *loc) { |
146 | | return *((uint64_t *) loc); |
| 263 | if ((((intptr_t) loc) & 3) == 0) |
| 264 | return *((uint64_t *) loc); |
| 265 | return (((uint64_t) read32le(loc)) << 32) | (uint64_t) read32le(loc + 4); |
147 | 266 | } |
148 | 267 | |
149 | 268 | static rtems_rtl_elf_rel_status |
150 | | rtems_rtl_elf_reloc_rela (rtems_rtl_obj* obj, |
| 269 | rtems_rtl_elf_reloc_rela (rtems_rtl_obj* obj, |
151 | 270 | const Elf_Rela* rela, |
152 | 271 | const rtems_rtl_obj_sect* sect, |
153 | 272 | const char* symname, |
154 | 273 | const Elf_Byte syminfo, |
155 | 274 | const Elf_Word symvalue, |
156 | 275 | const bool parsing) { |
157 | | Elf_Word *where; |
158 | | Elf_Word tmp; |
159 | | Elf_Word addend = (Elf_Word) rela->r_addend; |
160 | | Elf_Word local = 0; |
161 | | |
| 276 | Elf_Word *where = (Elf_Addr *)(sect->base + rela->r_offset); |
162 | 277 | char bits = (sizeof(Elf_Word) * 8); |
163 | | where = (Elf_Addr *)(sect->base + rela->r_offset); |
164 | 278 | |
165 | 279 | // Final PCREL value |
166 | 280 | Elf_Word pcrel_val = symvalue - ((Elf_Word) where); |
167 | 281 | |
168 | 282 | if (syminfo == STT_SECTION) { |
169 | | local = 1; |
170 | 283 | return rtems_rtl_elf_rel_no_error; |
171 | 284 | } |
172 | 285 | |
… |
… |
rtems_rtl_elf_reloc_rela (rtems_rtl_obj* obj, |
174 | 287 | return rtems_rtl_elf_rel_no_error; |
175 | 288 | } |
176 | 289 | |
| 290 | if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) { |
| 291 | const char* what = reloc_label(ELF_R_TYPE(rela->r_info)); |
| 292 | Elf_Word at_where = read32le(where); |
| 293 | printf("rtl: reloc base_rel(%s): %s: where=%p, *where=0x%" PRIx32 ", " |
| 294 | "addend=0x%" PRIu32 ", base %p\n", |
| 295 | rtems_rtl_obj_oname (obj), |
| 296 | what, where, at_where, rela->r_addend, sect->base); |
| 297 | } |
| 298 | |
177 | 299 | switch (ELF_R_TYPE(rela->r_info)) { |
178 | 300 | case R_TYPE(NONE): |
179 | 301 | break; |
180 | 302 | |
181 | 303 | case R_TYPE(RVC_BRANCH): { |
182 | | uint16_t insn = ((*where) & 0xFFFF) & 0xE383; |
| 304 | uint16_t insn = (read32le(where) & 0xFFFF) & 0xE383; |
183 | 305 | uint16_t imm8 = extractBits(pcrel_val, 8, 8) << 12; |
184 | 306 | uint16_t imm4_3 = extractBits(pcrel_val, 4, 3) << 10; |
185 | 307 | uint16_t imm7_6 = extractBits(pcrel_val, 7, 6) << 5; |
… |
… |
rtems_rtl_elf_reloc_rela (rtems_rtl_obj* obj, |
192 | 314 | break; |
193 | 315 | |
194 | 316 | case R_TYPE(RVC_JUMP): { |
195 | | uint16_t insn = ((*where) & 0xFFFF) & 0xE003; |
| 317 | uint16_t insn = (read32le(where) & 0xFFFF) & 0xE003; |
196 | 318 | uint16_t imm11 = extractBits(pcrel_val, 11, 11) << 12; |
197 | 319 | uint16_t imm4 = extractBits(pcrel_val, 4, 4) << 11; |
198 | 320 | uint16_t imm9_8 = extractBits(pcrel_val, 9, 8) << 9; |
… |
… |
rtems_rtl_elf_reloc_rela (rtems_rtl_obj* obj, |
232 | 354 | break; |
233 | 355 | |
234 | 356 | case R_TYPE(BRANCH): { |
235 | | |
236 | 357 | uint32_t insn = read32le(where) & 0x1FFF07F; |
237 | 358 | uint32_t imm12 = extractBits(pcrel_val, 12, 12) << 31; |
238 | 359 | uint32_t imm10_5 = extractBits(pcrel_val, 10, 5) << 25; |
… |
… |
rtems_rtl_elf_reloc_rela (rtems_rtl_obj* obj, |
252 | 373 | break; |
253 | 374 | |
254 | 375 | case R_TYPE(SET6): |
255 | | *((uint8_t *) where) = (*where & 0xc0) | (symvalue & 0x3f); |
| 376 | write8le(where, (read8le(where) & 0xc0) | (symvalue & 0x3f)); |
256 | 377 | break; |
257 | 378 | case R_TYPE(SET8): |
258 | | *((uint8_t *) where) = symvalue; |
| 379 | write8le(where, symvalue); |
259 | 380 | break; |
260 | 381 | case R_TYPE(SET16): |
261 | 382 | write16le(where, symvalue); |
… |
… |
rtems_rtl_elf_reloc_rela (rtems_rtl_obj* obj, |
265 | 386 | break; |
266 | 387 | |
267 | 388 | case R_TYPE(ADD8): |
268 | | *((uint8_t *) where) = *((uint8_t *) where) + symvalue; |
| 389 | write8le(where, read8le(where) + symvalue); |
269 | 390 | break; |
270 | 391 | case R_TYPE(ADD16): |
271 | 392 | write16le(where, read16le(where) + symvalue); |
… |
… |
rtems_rtl_elf_reloc_rela (rtems_rtl_obj* obj, |
278 | 399 | break; |
279 | 400 | |
280 | 401 | case R_TYPE(SUB6): |
281 | | *((uint8_t *) where) = (*where & 0xc0) | (((*where & 0x3f) - symvalue) & 0x3f); |
| 402 | write8le(where, (read8le(where) & 0xc0) | (((read8le(where) & 0x3f) - symvalue) & 0x3f)); |
282 | 403 | break; |
283 | 404 | case R_TYPE(SUB8): |
284 | | *((uint8_t *) where) = *((uint8_t *) where) - symvalue; |
| 405 | write8le(where, read8le(where) - symvalue); |
285 | 406 | break; |
286 | 407 | case R_TYPE(SUB16): |
287 | 408 | write16le(where, read16le(where) - symvalue); |
… |
… |
rtems_rtl_elf_reloc_rela (rtems_rtl_obj* obj, |
298 | 419 | |
299 | 420 | if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) |
300 | 421 | printf ("rtl: R_RISCV_32_PCREL %p @ %p in %s\n", |
301 | | (void *) * (where), where, rtems_rtl_obj_oname (obj)); |
| 422 | (void*) read32le(where), where, rtems_rtl_obj_oname (obj)); |
302 | 423 | |
303 | 424 | } |
304 | 425 | break; |
… |
… |
rtems_rtl_elf_reloc_rela (rtems_rtl_obj* obj, |
365 | 486 | |
366 | 487 | default: |
367 | 488 | rtems_rtl_set_error (EINVAL, |
368 | | "%s: Unsupported relocation type %ld " |
| 489 | "%s: Unsupported relocation type %" PRIu32 " " |
369 | 490 | "in non-PLT relocations", |
370 | 491 | sect->name, (uint32_t) ELF_R_TYPE(rela->r_info)); |
371 | 492 | return rtems_rtl_elf_rel_failure; |
diff --git a/cpukit/libdl/rtl-sym.c b/cpukit/libdl/rtl-sym.c
index 593069fba0..4fe08dcfaf 100644
a
|
b
|
rtems_rtl_symbol_obj_erase (rtems_rtl_obj* obj) |
299 | 299 | obj->global_syms = 0; |
300 | 300 | } |
301 | 301 | } |
| 302 | |
| 303 | bool |
| 304 | rtems_rtl_symbol_name_valid(const char* name) |
| 305 | { |
| 306 | if (name != NULL) |
| 307 | { |
| 308 | if (*name != '\0') |
| 309 | { |
| 310 | return true; |
| 311 | } |
| 312 | } |
| 313 | return false; |
| 314 | } |
diff --git a/cpukit/libdl/rtl-unresolved.c b/cpukit/libdl/rtl-unresolved.c
index 8e1c2abc90..c4c94e3f19 100644
a
|
b
|
|
24 | 24 | #include <string.h> |
25 | 25 | |
26 | 26 | #include <rtems/rtl/rtl.h> |
27 | | #include "rtl-error.h" |
28 | | #include <rtems/rtl/rtl-unresolved.h> |
| 27 | #include <rtems/rtl/rtl-sym.h> |
29 | 28 | #include <rtems/rtl/rtl-trace.h> |
| 29 | #include <rtems/rtl/rtl-unresolved.h> |
| 30 | |
| 31 | #include "rtl-error.h" |
30 | 32 | #include "rtl-trampoline.h" |
31 | 33 | |
32 | 34 | static rtems_rtl_unresolv_block* |
… |
… |
rtems_rtl_unresolved_add (rtems_rtl_obj* obj, |
547 | 549 | printf ("rtl: unresolv: add: %s(s:%d) -> %s\n", |
548 | 550 | rtems_rtl_obj_oname (obj), sect, name); |
549 | 551 | |
| 552 | if (!rtems_rtl_symbol_name_valid (name)) |
| 553 | return false; |
| 554 | |
550 | 555 | unresolved = rtems_rtl_unresolved_unprotected (); |
551 | 556 | if (!unresolved) |
552 | 557 | return false; |