arm_CallFunction.asm 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. ;-------------------------------------------------------------------------------------------------------
  2. ; Copyright (C) Microsoft. All rights reserved.
  3. ; Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. ;-------------------------------------------------------------------------------------------------------
  5. ;Var arm_CallFunction(JavascriptFunction* function, CallInfo info, uint count, Var* values, JavascriptMethod entryPoint)
  6. ;
  7. ; This method should be called as follows
  8. ; varResult = arm_CallFunction((JavascriptFunction*)function, args.Info, argCount, args.Values, entryPoint);
  9. ;
  10. ; and makes the following call
  11. ; return entryPoint(function, info, values[0], values[1], ..., values[n-2], values[n-1]);
  12. ; where n = info.Count >= 2 (so we know we'll need to pass two values in registers).
  13. ;
  14. ; ARM calling convention is:
  15. ; r0 parameter 1 = function
  16. ; r1 parameter 2 = info
  17. ; r2 values[0]
  18. ; r3 values[1]
  19. ; [sp+0] values[2]
  20. ; [sp+4] values[3]
  21. ; ...
  22. ;
  23. ; (4 bytes) return values are passed in r0.
  24. ;
  25. ; Since the 1st two parameters are the same for this method and the entry point, we don't need to touch them.
  26. ;
  27. OPT 2 ; disable listing
  28. #include "ksarm.h"
  29. #if defined(_CONTROL_FLOW_GUARD)
  30. IMPORT __guard_check_icall_fptr
  31. #endif
  32. OPT 1 ; re-enable listing
  33. TTL Lib\Runtime\Library\arm\arm_CallFunction.asm
  34. EXPORT arm_CallFunction
  35. IMPORT __chkstk ;See \\cpvsbuild\drops\dev11\Main\raw\current\sources\vctools\crt\crtw32\startup\arm\chkstk.asm.
  36. TEXTAREA
  37. NESTED_ENTRY arm_CallFunction
  38. ; IMPORTANT: the number of pushed registers (even vs odd) must be consistent with 8-bytes align check below.
  39. PROLOG_PUSH r4-r7,r11,lr ; r6 is saved for stack alignment, this does: add r11,sp,#10 as well
  40. #if defined(_CONTROL_FLOW_GUARD)
  41. PROLOG_PUSH r8-r9 ; extra register to save info across icall check, and one register to maintain alignment
  42. #endif
  43. PROLOG_STACK_SAVE r7 ; mov r7,sp -- save stack frame for restoring at the epilog.
  44. ;All but two values go onto the stack ... calculate the number of values on the stack.
  45. sub r4,r2,#2 ;subtract 2 == number of values that we can pass via registers.
  46. mov r5,r4,lsl #2 ;r5 = space needed on the stack for values.
  47. ; Adjust sp to meet ABI requirement: stack must be 8-bytes aligned at any function boundary.
  48. ; Each reg is 4 bytes, so as we push 4 (even) regs above, r1 == odd number of regs breaks 8-byte alignment, even is OK.
  49. asrs r12,r4,#1 ; r-shift r1 into carry - set carry flag if r4 is odd. Note: the value in r12 is not used.
  50. addcs r4,r4,#1 ; if carry is set, add space for one more argument on stack to guarantee 8-byte alignment.
  51. ; // TODO: Evanesco: it seems that keeping old values on stack can cause false-positive jcroot's. We should see if that's the case.
  52. ;Probe stack. This is required when we need more than 1 page of stack space.
  53. ;__chkstk will mark required number of pages as committed / throw stack overflow exception if can't.
  54. ; - input: r4 = the number of WORDS (word = 4 bytes) to allocate,
  55. ; - output: r4 = total number of BYTES probed/allocated.
  56. blx __chkstk ;now r4 = the space to allocate, r5 = actual space needed for values on stack, r4 >= r5.
  57. #if defined(_CONTROL_FLOW_GUARD)
  58. ldr r6,[sp, #32] ; r6 = entryPoint
  59. #else
  60. ldr r6,[sp, #24]
  61. #endif
  62. ;offset stack by the amount of space we'll need.
  63. sub sp,sp,r4
  64. add r3,r3,#8 ;add 8 to r3 (so it is the address of the first value to be placed on the stack).
  65. mov r12,#0 ;offset for getting values/storing on stack.
  66. |argN|
  67. cmp r5,r12
  68. beq arg2 ;if r5 == r12, no more values need to go onto the stack.
  69. ldr r4,[r3,r12] ;r3 = *(r2 + r12)
  70. str r4,[sp,r12] ;*(sp + r12) = r3
  71. add r12,r12,#4 ;offset increases by 4.
  72. b argN ;goto argN
  73. |arg2|
  74. ; Verify that the call target is valid, and process last two arguments
  75. #if defined(_CONTROL_FLOW_GUARD)
  76. mov r4, r0 ; save argument registers
  77. mov r5, r1
  78. mov r8, r3
  79. mov r0, r6 ; the target address to check
  80. mov32 r12, __guard_check_icall_fptr
  81. ldr r12, [r12]
  82. blx r12
  83. mov r0, r4 ; restore argument registers
  84. mov r1, r5
  85. mov r3, r8
  86. #endif
  87. ;Push values[0] into r2
  88. ldr r2,[r3,#-8] ;r2 = *(r2-8) = values[0]
  89. ;Push values[1] into r3
  90. ldr r3,[r3,#-4] ;r3 = *(r2-4) = values[1]
  91. blx r6 ;call r4 (== entry point)
  92. EPILOG_STACK_RESTORE r7
  93. #if defined(_CONTROL_FLOW_GUARD)
  94. EPILOG_POP r8-r9
  95. #endif
  96. EPILOG_POP r4-r7,r11,pc
  97. NESTED_END
  98. END