| // Mark stack as non-executable |
| #if defined(__linux__) && defined(__ELF__) |
| .section .note.GNU-stack, "", %progbits |
| #endif |
| |
| .text |
| .code 32 |
| .arm |
| .align |
| |
| .global upcall_new_stack |
| .global upcall_del_stack |
| .global __morestack |
| .hidden __morestack |
| |
| // r4 and r5 are scratch registers for __morestack due to llvm |
| // ARMFrameLowering::adjustForSegmentedStacks() implementation. |
| .type __morestack,%function |
| __morestack: |
| .fnstart |
| // Save frame pointer and return address |
| .save {r4, r5} |
| .save {lr} |
| .save {r6, fp, lr} |
| push {r6, fp, lr} |
| |
| .movsp r6 |
| mov r6, sp |
| .setfp fp, sp, #4 |
| add fp, sp, #4 |
| |
| // Save argument registers of the original function |
| push {r0, r1, r2, r3, lr} |
| |
| mov r0, r4 // The amount of stack needed |
| add r1, fp, #20 // Address of stack arguments |
| mov r2, r5 // Size of stack arguments |
| |
| // Create new stack |
| bl upcall_new_stack@plt |
| |
| // Hold new stack pointer |
| mov r5, r0 |
| |
| // Pop the saved arguments |
| pop {r0, r1, r2, r3, lr} |
| |
| // Grab the return pointer |
| add r4, lr, #16 // Skip past the return |
| mov sp, r5 // Swich to the new stack |
| mov lr, pc |
| mov pc, r4 // Call the original function |
| |
| // Switch back to rust stack |
| mov sp, r6 |
| |
| // Save return value |
| mov r4, r0 |
| mov r5, r1 |
| |
| // Remove the new allocated stack |
| bl upcall_del_stack@plt |
| |
| // Restore return value |
| mov r0, r4 |
| mov r1, r5 |
| |
| // Return |
| pop {r6, fp, lr} |
| mov pc, lr |
| .fnend |