dl-startup.h 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /*
  2. * Architecture specific code used by dl-startup.c
  3. * Copyright (C) 2016 Waldemar Brodkorb <wbx@uclibc-ng.org>
  4. * Ported from GNU libc
  5. * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
  6. */
  7. /* Copyright (C) 1995-2016 Free Software Foundation, Inc.
  8. The GNU C Library is free software; you can redistribute it and/or
  9. modify it under the terms of the GNU Lesser General Public License as
  10. published by the Free Software Foundation; either version 2.1 of the
  11. License, or (at your option) any later version.
  12. The GNU C Library is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. Lesser General Public License for more details.
  16. You should have received a copy of the GNU Lesser General Public
  17. License along with the GNU C Library; if not, see
  18. <http://www.gnu.org/licenses/>. */
  19. #include <features.h>
  20. __asm__("\
  21. .text \n\
  22. .globl _start \n\
  23. .type _start, %function \n\
  24. .globl _dl_start_user \n\
  25. .type _dl_start_user, %function \n\
  26. _start: \n\
  27. mov x0, sp \n\
  28. bl _dl_start \n\
  29. // returns user entry point in x0 \n\
  30. mov x21, x0 \n\
  31. _dl_start_user: \n\
  32. // get the original arg count \n\
  33. ldr x1, [sp] \n\
  34. // get the argv address \n\
  35. add x2, sp, #(1<<3) \n\
  36. // get _dl_skip_args to see if we were \n\
  37. // invoked as an executable \n\
  38. adrp x4, _dl_skip_args \n\
  39. ldr w4, [x4, #:lo12:_dl_skip_args] \n\
  40. // do we need to adjust argc/argv \n\
  41. cmp w4, 0 \n\
  42. beq .L_done_stack_adjust \n\
  43. // subtract _dl_skip_args from original arg count \n\
  44. sub x1, x1, x4 \n\
  45. // store adjusted argc back to stack \n\
  46. str x1, [sp] \n\
  47. // find the first unskipped argument \n\
  48. mov x3, x2 \n\
  49. add x4, x2, x4, lsl #3 \n\
  50. // shuffle envp down \n\
  51. 1: ldr x5, [x4], #(1<<3) \n\
  52. str x5, [x3], #(1<<3) \n\
  53. cmp x5, #0 \n\
  54. bne 1b \n\
  55. // shuffle auxv down \n\
  56. 1: ldp x0, x5, [x4, #(2<<3)]! \n\
  57. stp x0, x5, [x3], #(2<<3) \n\
  58. cmp x0, #0 \n\
  59. bne 1b \n\
  60. .L_done_stack_adjust: \n\
  61. // compute envp \n\
  62. add x3, x2, x1, lsl #3 \n\
  63. add x3, x3, #(1<<3) \n\
  64. // load the finalizer function \n\
  65. adrp x0, _dl_fini \n\
  66. add x0, x0, #:lo12:_dl_fini \n\
  67. // jump to the user_s entry point \n\
  68. br x21 \n\
  69. ");
  70. /* Get a pointer to the argv array. On many platforms this can be just
  71. * the address of the first argument, on other platforms we need to
  72. * do something a little more subtle here. */
  73. #define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long*)ARGS)+1)
  74. /* Handle relocation of the symbols in the dynamic loader. */
  75. static __always_inline
  76. void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, ElfW(Addr) *reloc_addr,
  77. ElfW(Addr) symbol_addr, ElfW(Addr) load_addr, ElfW(Addr) *sym)
  78. {
  79. switch (ELF_R_TYPE(rpnt->r_info)) {
  80. case R_AARCH64_NONE:
  81. break;
  82. case R_AARCH64_ABS64:
  83. case R_AARCH64_GLOB_DAT:
  84. case R_AARCH64_JUMP_SLOT:
  85. *reloc_addr = symbol_addr + rpnt->r_addend;
  86. break;
  87. default:
  88. _dl_exit(1);
  89. }
  90. }