* Tactic T0: Batch instructions that are not jump targets. * Assumes (overapproximate) control-flow-recovery */
| 800 | * Assumes (overapproximate) control-flow-recovery |
| 801 | */ |
| 802 | static Patch *tactic_T0(Binary &B, Instr *I, const Trampoline *T, |
| 803 | Tactic tactic = TACTIC_T0) |
| 804 | { |
| 805 | if (!option_tactic_T0 || !option_OCFR || !canPatch(I) || I->T != T) |
| 806 | return nullptr; |
| 807 | |
| 808 | // Step (1): build batch backwards, up to limit or target reached. |
| 809 | Instr *J = I; |
| 810 | size_t size = 0; |
| 811 | for (unsigned limit = T0_LIMIT; !J->target && limit > 0; limit--) |
| 812 | { |
| 813 | size += J->size; |
| 814 | Instr *K = J->pred(); |
| 815 | if (K == nullptr || |
| 816 | (K->STATE[0] != STATE_INSTRUCTION && |
| 817 | K->STATE[0] != STATE_QUEUED)) |
| 818 | break; |
| 819 | J = K; |
| 820 | } |
| 821 | |
| 822 | // Step (2): Build batch fowards until sizeof(jmpq), or a CFT. |
| 823 | Instr *L = I; |
| 824 | bool cft = false; // isUnconditionalCFT(I); |
| 825 | while (!cft && size < /*sizeof(jmpq)=*/5) |
| 826 | { |
| 827 | Instr *K = L->succ(); |
| 828 | if (K == nullptr || K->target || !canPatch(K) || |
| 829 | (K->is_patched && !K->is_evicted)) |
| 830 | break; |
| 831 | L = K; |
| 832 | size += L->size; |
| 833 | cft = isCFT(L->ORIG, L->size, CFT_CALL | CFT_RET | CFT_JMP); |
| 834 | } |
| 835 | if (J == L) |
| 836 | return nullptr; // Batch is a single instruction == T0 failed |
| 837 | |
| 838 | // Step (3): "Free" all batched instructions. |
| 839 | Patch *P = nullptr; |
| 840 | for (Instr *K = L; K != nullptr && K->addr >= J->addr; K = K->pred()) |
| 841 | { |
| 842 | Patch *Q = new Patch(K, TACTIC_T0, nullptr); |
| 843 | patchUnused(Q, /*offset=*/0); |
| 844 | Q->next = P; |
| 845 | P = Q; |
| 846 | } |
| 847 | |
| 848 | // Step (4): Build batch trampoline. |
| 849 | Trampoline *U = nullptr; |
| 850 | { |
| 851 | size_t num_entries = 1; |
| 852 | uint8_t *ptr = |
| 853 | new uint8_t[sizeof(Trampoline) + num_entries * sizeof(Entry)]; |
| 854 | U = (Trampoline *)ptr; |
| 855 | U->prot = PROT_READ | PROT_EXEC; |
| 856 | U->num_entries = num_entries; |
| 857 | U->preload = false; |
| 858 | U->entries[0].kind = ENTRY_BATCH; |
| 859 | U->entries[0].length = 0; |