relocate.c 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. /*
  2. * Copyright (C) 2013-2014 Synopsys, Inc. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: GPL-2.0+
  5. */
  6. #include <common.h>
  7. #include <elf.h>
  8. #include <asm/sections.h>
  9. DECLARE_GLOBAL_DATA_PTR;
  10. /*
  11. * Base functionality is taken from x86 version with added ARC-specifics
  12. */
  13. int do_elf_reloc_fixups(void)
  14. {
  15. Elf32_Rela *re_src = (Elf32_Rela *)(&__rel_dyn_start);
  16. Elf32_Rela *re_end = (Elf32_Rela *)(&__rel_dyn_end);
  17. Elf32_Addr *offset_ptr_rom, *last_offset = NULL;
  18. Elf32_Addr *offset_ptr_ram;
  19. do {
  20. /* Get the location from the relocation entry */
  21. offset_ptr_rom = (Elf32_Addr *)re_src->r_offset;
  22. /* Check that the location of the relocation is in .text */
  23. if (offset_ptr_rom >= (Elf32_Addr *)&__image_copy_start &&
  24. offset_ptr_rom > last_offset) {
  25. unsigned int val;
  26. /* Switch to the in-RAM version */
  27. offset_ptr_ram = (Elf32_Addr *)((ulong)offset_ptr_rom +
  28. gd->reloc_off);
  29. /*
  30. * Use "memcpy" because target location might be
  31. * 16-bit aligned on ARC so we may need to read
  32. * byte-by-byte. On attempt to read entire word by
  33. * CPU throws an exception
  34. */
  35. memcpy(&val, offset_ptr_ram, sizeof(int));
  36. #ifdef __LITTLE_ENDIAN__
  37. /* If location in ".text" section swap value */
  38. if ((unsigned int)offset_ptr_rom <
  39. (unsigned int)&__ivt_end)
  40. val = (val << 16) | (val >> 16);
  41. #endif
  42. /* Check that the target points into executable */
  43. if (val >= (unsigned int)&__image_copy_start && val <=
  44. (unsigned int)&__image_copy_end) {
  45. val += gd->reloc_off;
  46. #ifdef __LITTLE_ENDIAN__
  47. /* If location in ".text" section swap value */
  48. if ((unsigned int)offset_ptr_rom <
  49. (unsigned int)&__ivt_end)
  50. val = (val << 16) | (val >> 16);
  51. #endif
  52. memcpy(offset_ptr_ram, &val, sizeof(int));
  53. }
  54. }
  55. last_offset = offset_ptr_rom;
  56. } while (++re_src < re_end);
  57. return 0;
  58. }