gprt0.as 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /* This is the canonical entry point, usually the first thing in the text
  2. segment. The SVR4/i386 ABI (pages 3-31, 3-32) says that when the entry
  3. point runs, most registers' values are unspecified, except for:
  4. %rdx Contains a function pointer to be registered with `atexit'.
  5. This is how the dynamic linker arranges to have DT_FINI
  6. functions called for shared libraries that have been loaded
  7. before this code runs.
  8. %rsp The stack contains the arguments and environment:
  9. 0(%rsp) argc
  10. 8(%rsp) argv[0]
  11. ...
  12. (8*argc)(%rsp) NULL
  13. (8*(argc+1))(%rsp) envp[0]
  14. ...
  15. NULL
  16. */
  17. .text
  18. .globl _start
  19. .type _start,@function
  20. _start:
  21. /* Clear the frame pointer. The ABI suggests this be done, to mark
  22. the outermost frame obviously. */
  23. xorq %rbp, %rbp
  24. /* Extract the arguments as encoded on the stack and set up
  25. the arguments for __libc_start_main (int (*main) (int, char **, char **),
  26. int argc, char *argv,
  27. void (*init) (void), void (*fini) (void),
  28. void (*rtld_fini) (void), void *stack_end).
  29. The arguments are passed via registers and on the stack:
  30. main: %rdi
  31. argc: %rsi
  32. argv: %rdx
  33. init: %rcx
  34. fini: %r8
  35. rtld_fini: %r9
  36. stack_end: stack. */
  37. movq %rdx, %r9 /* Address of the shared library termination
  38. function. */
  39. popq %rsi /* Pop the argument count. */
  40. movq %rsp, %rdx /* argv starts just at the current stack top. */
  41. movq entryinfo@GOTPCREL(%rip),%r10 /* load address of entryinfo variable */
  42. movq %rsi,56(%r10)
  43. movq %rsp,64(%r10) /* argv starts just at the current stack top */
  44. leaq 8(,%rsi,8),%rax
  45. addq %rsp,%rax
  46. movq %rax,72(%r10)
  47. /* Align the stack to a 16 byte boundary to follow the ABI. */
  48. andq $~15, %rsp
  49. pushq %rax /* Push garbage because we push 8 more bytes. */
  50. /* Provide the highest stack address to the user code (for stacks
  51. which grow downwards). */
  52. pushq %rsp
  53. /* Pass address of our own entry points to .fini and .init. */
  54. movq _init_dummy@GOTPCREL(%rip), %r8
  55. movq _fini_dummy@GOTPCREL(%rip), %rcx
  56. movq main_stub@GOTPCREL(%rip), %rdi
  57. /* Call the user's main function, and exit with its value.
  58. But let the libc call main. */
  59. call __libc_start_main@PLT
  60. hlt /* Crash if somehow `exit' does return. */
  61. /* fake main routine which will be run from libc */
  62. .globl main_stub
  63. .type main_stub,@function
  64. main_stub:
  65. /* save return address */
  66. popq %rax
  67. // stack alignment
  68. pushq %rax
  69. movq ___fpc_ret_rbp@GOTPCREL(%rip),%rcx
  70. movq %rbp,(%rcx)
  71. movq ___fpc_ret@GOTPCREL(%rip),%rcx
  72. movq %rax,(%rcx)
  73. pushq %rax
  74. /* Initialize gmon */
  75. movq _etext@GOTPCREL(%rip),%rsi
  76. movq _start@GOTPCREL(%rip),%rdi
  77. call monstartup@PLT
  78. movq _mcleanup@GOTPCREL(%rip),%rdi
  79. call atexit@PLT
  80. /* fill the remaining fields of the entry information */
  81. movq entryinfo@GOTPCREL(%rip),%rdi /* load address of entryinfo variable into argument for SysEntry*/
  82. /* Save initial stackpointer */
  83. movq %rsp,80(%rdi)
  84. /* store stack length */
  85. movq __stklen@GOTPCREL(%rip),%rax
  86. movq %rax,88(%rdi)
  87. /* store pointer to _haltproc */
  88. movq _haltproc@GOTPCREL(%rip),%rax
  89. movq %rax,96(%rdi)
  90. /* populate the table pointers */
  91. movq INITFINAL@GOTPCREL(%rip),%rax
  92. movq %rax,(%rdi)
  93. movq FPC_THREADVARTABLES@GOTPCREL(%rip),%rax
  94. movq %rax,8(%rdi)
  95. movq FPC_RESOURCESTRINGTABLES@GOTPCREL(%rip),%rax
  96. movq %rax,16(%rdi)
  97. movq FPC_RESSTRINITTABLES@GOTPCREL(%rip),%rax
  98. movq %rax,24(%rdi)
  99. movq FPC_RESLOCATION@GOTPCREL(%rip),%rax
  100. movq %rax,32(%rdi)
  101. movq PASCALMAIN@GOTPCREL(%rip),%rax
  102. movq %rax,40(%rdi)
  103. /* valgrind_used can stay 0 */
  104. /* start the program */
  105. xorq %rbp,%rbp
  106. call FPC_SysEntry@PLT
  107. hlt
  108. .size main_stub,.-main_stub
  109. .globl _haltproc
  110. .type _haltproc,@function
  111. _haltproc:
  112. movq operatingsystem_result@GOTPCREL(%rip),%rax
  113. movzwl (%rax),%eax
  114. /* return to libc */
  115. movq ___fpc_ret_rbp@GOTPCREL(%rip),%rcx
  116. movq (%rcx),%rbp
  117. movq ___fpc_ret@GOTPCREL(%rip),%rcx
  118. movq (%rcx),%rdx
  119. pushq %rdx
  120. ret
  121. .size _haltproc,.-_haltproc
  122. .globl _init_dummy
  123. .type _init_dummy, @function
  124. _init_dummy:
  125. ret
  126. .size _init_dummy,.-_init_dummy
  127. .globl _fini_dummy
  128. .type _fini_dummy, @function
  129. _fini_dummy:
  130. ret
  131. .size _fini_dummy,.-_fini_dummy
  132. /* Define a symbol for the first piece of initialized data. */
  133. .data
  134. .globl __data_start
  135. __data_start:
  136. .long 0
  137. .weak data_start
  138. data_start = __data_start
  139. .globl ___fpc_brk_addr /* heap management */
  140. .type ___fpc_brk_addr,@object
  141. .size ___fpc_brk_addr,8
  142. ___fpc_brk_addr:
  143. .quad 0
  144. ___fpc_ret: /* return address to libc */
  145. .quad 0
  146. ___fpc_ret_rbp:
  147. .quad 0
  148. .bss
  149. /* the entry information looks like this:
  150. TEntryInformation = record
  151. InitFinalTable : Pointer; // offset 0
  152. ThreadvarTablesTable : Pointer; // offset 8
  153. ResourceStringTables : Pointer; // offset 16
  154. ResStrInitTables : Pointer; // offset 24
  155. ResLocation : Pointer; // offset 32
  156. PascalMain : Procedure; // offset 40
  157. valgrind_used : boolean; // offset 48
  158. OS : TEntryInformationOS; // offset 56
  159. end;
  160. with TEntryInformationOS being
  161. TEntryInformationOS = record
  162. argc: longint; // offset 56
  163. argv: ppchar; // offset 64
  164. envp: ppchar; // offset 72
  165. stkptr: pointer; // offset 80
  166. stklen: sizeuint; // offset 88
  167. haltproc: procedure(e:longint);cdecl; // offset 96
  168. end;
  169. The size of TEntryInformationOS including padding is 5 * sizeof(Pointer) = 40
  170. The size of TEntryInformation including padding without OS is 8 * sizeof(Pointer) = 64
  171. Thus the total size of TEntryInformation including padding is 104
  172. */
  173. .comm entryinfo,104
  174. /* We need this stuff to make gdb behave itself, otherwise
  175. gdb will chokes with SIGILL when trying to debug apps.
  176. */
  177. .section ".note.ABI-tag", "a"
  178. .align 4
  179. .long 1f - 0f
  180. .long 3f - 2f
  181. .long 1
  182. 0: .asciz "GNU"
  183. 1: .align 4
  184. 2: .long 0
  185. .long 2,4,0
  186. 3: .align 4
  187. .section .note.GNU-stack,"",@progbits