RCTProfileTrampoline-x86_64.S 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /**
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #include "RCTDefines.h"
  8. #include "RCTMacros.h"
  9. #if RCT_PROFILE && defined(__x86_64__)
  10. .globl SYMBOL_NAME(RCTProfileTrampoline)
  11. SYMBOL_NAME(RCTProfileTrampoline):
  12. /**
  13. * Saves all the state so we can restore it before calling the functions being
  14. * profiled. Registers have the same value at the point of the function call,
  15. * the only thing we can change is the return value, so we return to
  16. * `RCTProfileTrampoline` rather than to its caller.
  17. *
  18. * Save all the parameters registers (%rdi, %rsi, %rdx, %rcx, %r8, %r9), they
  19. * have the 6 first arguments of the function call, and %rax which in special
  20. * cases might be a pointer used for struct returns.
  21. *
  22. * We have to save %r12 since its value should be preserved across function
  23. * calls and we'll use it to keep the stack pointer
  24. */
  25. subq $0x80+8, %rsp // 8 x 16-bytes xmm registers + 8-bytes alignment
  26. movdqa %xmm0, 0x70(%rsp)
  27. movdqa %xmm1, 0x60(%rsp)
  28. movdqa %xmm2, 0x50(%rsp)
  29. movdqa %xmm3, 0x40(%rsp)
  30. movdqa %xmm4, 0x30(%rsp)
  31. movdqa %xmm5, 0x20(%rsp)
  32. movdqa %xmm6, 0x10(%rsp)
  33. movdqa %xmm7, 0x00(%rsp)
  34. pushq %rdi
  35. pushq %rsi
  36. pushq %rdx
  37. pushq %rcx
  38. pushq %r8
  39. pushq %r9
  40. pushq %rax
  41. pushq %r12
  42. /**
  43. * Store the stack pointer in the callee saved register %r12 and align the
  44. * stack - it has to 16-byte aligned at the point of the function call
  45. */
  46. movq %rsp, %r12
  47. andq $-0x10, %rsp
  48. /**
  49. * void RCTProfileGetImplementation(id object, SEL selector)
  50. *
  51. * This is a C function defined in `RCTProfile.m`, the object and the selector
  52. * already have to be on %rdi and %rsi respectively, as in any ObjC call.
  53. */
  54. callq SYMBOL_NAME_PIC(RCTProfileGetImplementation)
  55. // Restore/unalign the stack pointer, so we can access the registers we stored
  56. movq %r12, %rsp
  57. /**
  58. * pop %r12 before pushing %rax, which contains the address of the actual
  59. * function we have to call, than we keep %r12 at the bottom of the stack to
  60. * reference the stack pointer
  61. */
  62. popq %r12
  63. pushq %rax
  64. pushq %r12
  65. // align stack
  66. movq %rsp, %r12
  67. andq $-0x10, %rsp
  68. /**
  69. * Allocate memory to save parent before start profiling: the address is put
  70. * at the bottom of the stack at the function call, so ret can actually return
  71. * to the caller. In this case it has the address of RCTProfileTrampoline's
  72. * caller where we'll have to return to after we're finished.
  73. *
  74. * We can't store it on the stack or in any register, since we have to be in
  75. * the exact same state we were at the moment we were called, so the solution
  76. * is to allocate a tiny bit of memory to save this address
  77. */
  78. // allocate 16 bytes
  79. movq $0x10, %rdi
  80. callq SYMBOL_NAME_PIC(RCTProfileMalloc)
  81. // store the initial value of calle saved registers %r13 and %r14
  82. movq %r13, 0x0(%rax)
  83. movq %r14, 0x8(%rax)
  84. // mov the pointers we need to the callee saved registers
  85. movq 0xd8(%rsp), %r13 // caller of RCTProfileTrampoline (0xd8 is stack top)
  86. movq %rax, %r14 // allocated memory's address
  87. /**
  88. * Move self and cmd back to the registers and call start profile: it uses
  89. * the object and the selector to label the call in the profile.
  90. */
  91. movq 0x40(%r12), %rdi // object
  92. movq 0x38(%r12), %rsi // selector
  93. // void RCTProfileTrampolineStart(id, SEL) in RCTProfile.m
  94. callq SYMBOL_NAME_PIC(RCTProfileTrampolineStart)
  95. // unalign the stack and restore %r12
  96. movq %r12, %rsp
  97. popq %r12
  98. // Restore registers for actual function call
  99. popq %r11
  100. popq %rax
  101. popq %r9
  102. popq %r8
  103. popq %rcx
  104. popq %rdx
  105. popq %rsi
  106. popq %rdi
  107. movdqa 0x00(%rsp), %xmm7
  108. movdqa 0x10(%rsp), %xmm6
  109. movdqa 0x20(%rsp), %xmm5
  110. movdqa 0x30(%rsp), %xmm4
  111. movdqa 0x40(%rsp), %xmm3
  112. movdqa 0x50(%rsp), %xmm2
  113. movdqa 0x60(%rsp), %xmm1
  114. movdqa 0x70(%rsp), %xmm0
  115. addq $0x80+8, %rsp
  116. /**
  117. * delete parent caller (saved in %r13) `call` will add the new address so
  118. * we return to RCTProfileTrampoline rather than to its caller
  119. */
  120. addq $0x8, %rsp
  121. // call the actual function and save the return value
  122. callq *%r11
  123. pushq %rax
  124. pushq %rdx
  125. subq $0x20, %rsp // 2 16-bytes xmm register
  126. movdqa %xmm0, 0x00(%rsp)
  127. movdqa %xmm1, 0x10(%rsp)
  128. // void RCTProfileTrampolineEnd(void) in RCTProfile.m - just ends this profile
  129. callq SYMBOL_NAME_PIC(RCTProfileTrampolineEnd)
  130. /**
  131. * Restore the initial value of the callee saved registers, saved in the
  132. * memory allocated.
  133. */
  134. movq %r13, %rcx
  135. movq %r14, %rdi
  136. movq 0x0(%r14), %r13
  137. movq 0x8(%r14), %r14
  138. /**
  139. * save caller address and actual function return (previously in the allocated
  140. * memory) and align the stack
  141. */
  142. pushq %rcx
  143. pushq %r12
  144. movq %rsp, %r12
  145. andq $-0x10, %rsp
  146. // Free the memory allocated to stash callee saved registers
  147. callq SYMBOL_NAME_PIC(RCTProfileFree)
  148. // unalign stack and restore %r12
  149. movq %r12, %rsp
  150. popq %r12
  151. /**
  152. * pop the caller address to %rcx and the actual function return value(s)
  153. * so it's the return value of RCTProfileTrampoline
  154. */
  155. popq %rcx
  156. movdqa 0x00(%rsp), %xmm0
  157. movdqa 0x10(%rsp), %xmm1
  158. addq $0x20, %rsp
  159. popq %rdx
  160. popq %rax
  161. // jump to caller
  162. jmpq *%rcx
  163. #endif