dl-startup.h 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. /*
  2. * Architecture specific code used by dl-startup.c
  3. * Copyright (C) 2005 by Erik Andersen <andersen@codepoet.org>
  4. */
  5. /* Perform operation OP with PC-relative SRC as the first operand and
  6. * DST as the second. TMP is available as a temporary if needed. */
  7. #ifdef __mcoldfire__
  8. #define PCREL_OP(OP, SRC, DST, TMP, PC) \
  9. "move.l #" SRC " - ., " TMP "\n\t" OP " (-8, " PC ", " TMP "), " DST
  10. #else
  11. #define PCREL_OP(OP, SRC, DST, TMP, PC) \
  12. OP " " SRC "(" PC "), " DST
  13. #endif
  14. __asm__ ("\
  15. .text\n\
  16. .globl _start\n\
  17. .type _start,@function\n\
  18. .hidden _start\n\
  19. _start:\n\
  20. move.l %sp, -(%sp)\n\
  21. jbsr _dl_start\n\
  22. addq.l #4, %sp\n\
  23. /* FALLTHRU */\n\
  24. \n\
  25. .globl _dl_start_user\n\
  26. .type _dl_start_user,@function\n\
  27. _dl_start_user:\n\
  28. # Save the user entry point address in %a4.\n\
  29. move.l %d0, %a4\n\
  30. # See if we were run as a command with the executable file\n\
  31. # name as an extra leading argument.\n\
  32. " PCREL_OP ("move.l", "_dl_skip_args", "%d0", "%d0", "%pc") "\n\
  33. # Pop the original argument count\n\
  34. move.l (%sp)+, %d1\n\
  35. # Subtract _dl_skip_args from it.\n\
  36. sub.l %d0, %d1\n\
  37. # Adjust the stack pointer to skip _dl_skip_args words.\n\
  38. lea (%sp, %d0*4), %sp\n\
  39. # Push back the modified argument count.\n\
  40. move.l %d1, -(%sp)\n\
  41. # Pass our finalizer function to the user in %a1.\n\
  42. " PCREL_OP ("lea", "_dl_fini", "%a1", "%a1", "%pc") "\n\
  43. # Initialize %fp with the stack pointer.\n\
  44. move.l %sp, %fp\n\
  45. # Jump to the user's entry point.\n\
  46. jmp (%a4)\n\
  47. .size _dl_start_user, . - _dl_start_user\n\
  48. .previous");
  49. /* Get a pointer to the argv array. On many platforms this can be just
  50. * the address of the first argument, on other platforms we need to
  51. * do something a little more subtle here. */
  52. #define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long *) ARGS) + 1)
  53. /* Handle relocation of the symbols in the dynamic loader. */
  54. static __always_inline
  55. void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, unsigned long *reloc_addr,
  56. unsigned long symbol_addr, unsigned long load_addr, Elf32_Sym *symtab)
  57. {
  58. switch (ELF_R_TYPE(rpnt->r_info))
  59. {
  60. case R_68K_8:
  61. *(char *) reloc_addr = symbol_addr + rpnt->r_addend;
  62. break;
  63. case R_68K_16:
  64. *(short *) reloc_addr = symbol_addr + rpnt->r_addend;
  65. break;
  66. case R_68K_32:
  67. *reloc_addr = symbol_addr + rpnt->r_addend;
  68. break;
  69. case R_68K_PC8:
  70. *(char *) reloc_addr = (symbol_addr + rpnt->r_addend
  71. - (unsigned int) reloc_addr);
  72. break;
  73. case R_68K_PC16:
  74. *(short *) reloc_addr = (symbol_addr + rpnt->r_addend
  75. - (unsigned int) reloc_addr);
  76. break;
  77. case R_68K_PC32:
  78. *reloc_addr = (symbol_addr + rpnt->r_addend
  79. - (unsigned int) reloc_addr);
  80. break;
  81. case R_68K_GLOB_DAT:
  82. case R_68K_JMP_SLOT:
  83. *reloc_addr = symbol_addr;
  84. break;
  85. case R_68K_RELATIVE:
  86. *reloc_addr = ((unsigned int) load_addr +
  87. (rpnt->r_addend ? : *reloc_addr));
  88. break;
  89. default:
  90. _dl_exit (1);
  91. }
  92. }