* Send a call ELF trampoline. */
| 1857 | * Send a call ELF trampoline. |
| 1858 | */ |
| 1859 | unsigned e9tool::sendCallTrampolineMessage(FILE *out, const char *name, |
| 1860 | const Call &call) |
| 1861 | { |
| 1862 | sendELFFileMessage(out, call.target); |
| 1863 | |
| 1864 | bool sysv = true; |
| 1865 | switch (call.target->type) |
| 1866 | { |
| 1867 | case BINARY_TYPE_PE_EXE: case BINARY_TYPE_PE_DLL: |
| 1868 | sysv = false; |
| 1869 | break; |
| 1870 | default: |
| 1871 | break; |
| 1872 | } |
| 1873 | |
| 1874 | const char *patch = name+1; |
| 1875 | sendMessageHeader(out, "trampoline"); |
| 1876 | sendParamHeader(out, "name"); |
| 1877 | sendString(out, name); |
| 1878 | sendSeparator(out); |
| 1879 | sendParamHeader(out, "template"); |
| 1880 | putc('[', out); |
| 1881 | |
| 1882 | // Adjust the stack: |
| 1883 | fprintf(out, "%u,%u,%u,%u,{\"int32\":%d},", // lea -0x4000(%rsp),%rsp |
| 1884 | 0x48, 0x8d, 0xa4, 0x24, -0x4000); |
| 1885 | |
| 1886 | // Push all caller-save registers: |
| 1887 | bool conditional = (call.jmp != JUMP_NONE); |
| 1888 | bool clean = (call.abi == ABI_CLEAN); |
| 1889 | bool state = call.state; |
| 1890 | const int *rsave = getCallerSaveRegs(sysv, clean, state, conditional, |
| 1891 | call.nargs); |
| 1892 | int num_rsave = 0; |
| 1893 | Register rscratch = (clean || state? REGISTER_RAX: REGISTER_INVALID); |
| 1894 | int32_t offset = 0x4000; |
| 1895 | for (int i = 0; rsave[i] >= 0; i++, num_rsave++) |
| 1896 | { |
| 1897 | sendPush(out, offset, (call.pos != POS_AFTER), getReg(rsave[i]), |
| 1898 | rscratch); |
| 1899 | if (rsave[i] != RSP_IDX && rsave[i] != RIP_IDX) |
| 1900 | offset += sizeof(int64_t); |
| 1901 | } |
| 1902 | |
| 1903 | // Load the arguments: |
| 1904 | fprintf(out, "\"$ARGS@%s\",", patch); |
| 1905 | if (!sysv) |
| 1906 | { |
| 1907 | // lea -0x20(%rsp),%rsp # MS ABI red-zone |
| 1908 | fprintf(out, "%u,%u,%u,%u,{\"int8\":%d},", |
| 1909 | 0x48, 0x8d, 0x64, 0x24, -0x20); |
| 1910 | } |
| 1911 | |
| 1912 | // Call the function: |
| 1913 | fprintf(out, "%u,\"$FUNC@%s\",", 0xe8, patch); // callq function |
| 1914 | |
| 1915 | // Restore the state: |
| 1916 | if (!sysv) |