diff --git a/cTools/libs/arch/aarch64/aarch64.c b/cTools/libs/arch/aarch64/aarch64.c index 0216676..9d428a9 100644 --- a/cTools/libs/arch/aarch64/aarch64.c +++ b/cTools/libs/arch/aarch64/aarch64.c @@ -675,3 +675,23 @@ uint8_t aarch64_put_cb( uint32_t *dst return 4; } +uint8_t aarch64_put_tb( uint32_t *dst + , uint64_t pc + , uint64_t target_addr + , uint8_t reg_num + , bool non_zero + , bool x64 + , uint8_t bit_pos + ) +{ + int64_t imm14 = SIGN_EXTEND((int64_t)(target_addr - pc) >> 2, 13); + + *dst = (x64 ? 0x10000000 : 0x0) + | (uint32_t)0x36000000 + | (non_zero ? 0x01000000 : 0x0) + | (uint32_t)(bit_pos & 0x1f) << 19 + | (uint32_t)(imm14 & 0x3FFF) << 5 + | (uint32_t)(reg_num & 0x1F); + + return 4; +} diff --git a/cTools/libs/arch/aarch64/aarch64.h b/cTools/libs/arch/aarch64/aarch64.h index 0644f64..2a8eca9 100644 --- a/cTools/libs/arch/aarch64/aarch64.h +++ b/cTools/libs/arch/aarch64/aarch64.h @@ -282,5 +282,15 @@ uint8_t aarch64_put_cb( uint32_t *dst , bool x64 ); +EXPORT_FUNC +uint8_t aarch64_put_tb( uint32_t *dst + , uint64_t pc + , uint64_t target_addr + , uint8_t reg_num + , bool non_zero + , bool x64 + , uint8_t bit_pos + ); + #endif /* __AARCH64_H */ diff --git a/cTools/libs/arch/aarch64/aarch64_code_move.c b/cTools/libs/arch/aarch64/aarch64_code_move.c index 2e5dbbe..48d5d3e 100644 --- a/cTools/libs/arch/aarch64/aarch64_code_move.c +++ b/cTools/libs/arch/aarch64/aarch64_code_move.c @@ -354,7 +354,7 @@ aarch64_move_b_cond( uint32_t instr uint64_t new_target_addr = new_pc + ((uint64_t)new_imm19 << 2); if (target_addr == new_target_addr) { STDERROR_LOG("BC\n"); - // We can fit offset into 26 bits. + // We can fit offset into 19 bits. r->type = RELOC_AARCH64_B_COND; r->new_size = aarch64_put_b_cond( (uint32_t*)dst , new_pc @@ -399,7 +399,7 @@ aarch64_move_cb( uint32_t instr uint64_t new_target_addr = new_pc + ((uint64_t)new_imm19 << 2); if (target_addr == new_target_addr) { STDERROR_LOG("CB\n"); - // We can fit offset into 26 bits. + // We can fit offset into 19 bits. r->type = RELOC_AARCH64_CB; r->new_size = aarch64_put_cb( (uint32_t*)dst , new_pc @@ -415,6 +415,50 @@ aarch64_move_cb( uint32_t instr return r->new_size; } +static uint8_t +aarch64_move_tb( uint32_t instr + , uint8_t *dst + , uint64_t old_pc + , uint64_t new_pc + , vt_sorted_vector_t *rel + ) +{ + bt_reloc *r = GET_PRE_INIT_BT_RELOC(rel); + bool x64 = !!(instr & 0x80000000); + bool non_zero = !!(instr & 0x01000000); + uint8_t reg_num = instr & 0x1F; + int64_t imm14 = SIGN_EXTEND((instr >> 5) & 0x3FFF, 13); + uint8_t bit_pos = (x64 ? 0x20 : 0) + | ((instr & 0x00f80000) >> 19); + + uint64_t target_addr = old_pc + ((uint64_t)imm14 << 2); + r->old_target = target_addr; + target_addr = get_instr_new_addr(target_addr, rel); + r->new_target = target_addr; + + int64_t new_imm14 = ((target_addr - new_pc) >> 2) & 0x3FFF; + new_imm14 = SIGN_EXTEND(new_imm14, 13); + + uint64_t new_target_addr = new_pc + ((uint64_t)new_imm14 << 2); + if (target_addr == new_target_addr) { + // We can fit offset into 14 bits. + r->type = RELOC_AARCH64_TB; + r->new_size = aarch64_put_tb( (uint32_t*)dst + , new_pc + , target_addr + , reg_num + , non_zero + , x64 + , bit_pos + ); + } else { + STDERROR_LOG("TB: cannot fit in the 11 bits\n"); + } + + return r->new_size; + +} + CODE_MOVE_ERROR aarch64_instr_move( const uint8_t *src , uint8_t *dst @@ -501,6 +545,15 @@ aarch64_instr_move( const uint8_t *src STDERROR_LOG("CB: new instr: %"PRIx32"\n", *(uint32_t*)dst); break; } + case AARCH64_INSTR_OP_TBZ32: + case AARCH64_INSTR_OP_TBNZ32: + case AARCH64_INSTR_OP_TBZ64: + FALLTHROUGH; + case AARCH64_INSTR_OP_TBNZ64: + { + r->new_size = aarch64_move_tb(instr, dst, old_pc, new_pc, rel); + break; + } case AARCH64_INSTR_OP_BCEQ: case AARCH64_INSTR_OP_BCNE: case AARCH64_INSTR_OP_BCCS: @@ -517,10 +570,6 @@ aarch64_instr_move( const uint8_t *src case AARCH64_INSTR_OP_BCLE: case AARCH64_INSTR_OP_RETAASPPC: case AARCH64_INSTR_OP_RETABSPPC: - case AARCH64_INSTR_OP_TBZ32: - case AARCH64_INSTR_OP_TBNZ32: - case AARCH64_INSTR_OP_TBZ64: - case AARCH64_INSTR_OP_TBNZ64: case AARCH64_INSTR_OP_LDRF32: case AARCH64_INSTR_OP_LDRF64: case AARCH64_INSTR_OP_LDRF128: @@ -767,6 +816,28 @@ resolve_relocations( vt_sorted_vector_t *rel STDERROR_LOG("\tFinal CB: %"PRIx32"\n", *(uint32_t*)instr_p); break; } + case RELOC_AARCH64_TB: + { + STDERROR_LOG("Reloc CB:\n"); + STDERROR_LOG("\told_target: 0x%"PRIx64", new_pc_old_target: 0x%"PRIx64"\n", r[i].old_target + , old_target->new_pc); + bool x64 = !!((*((uint32_t*)instr_p)) & 0x80000000); + bool non_zero = !!((*((uint32_t*)instr_p)) & 0x01000000); + uint8_t bit_pos = (x64 ? 0x20 : 0) + | (((*((uint32_t*)instr_p)) & 0x00f80000) >> 19); + + STDERROR_LOG("\tPre Final CB: %"PRIx32"\n", *(uint32_t*)instr_p); + aarch64_put_tb( (uint32_t*)instr_p + , r[i].new_pc + , r[i].new_target + , reg_num + , non_zero + , x64 + , bit_pos + ); + STDERROR_LOG("\tFinal CB: %"PRIx32"\n", *(uint32_t*)instr_p); + break; + } default: break; } diff --git a/cTools/libs/arch/code_move.h b/cTools/libs/arch/code_move.h index 0145f71..6f1ee44 100644 --- a/cTools/libs/arch/code_move.h +++ b/cTools/libs/arch/code_move.h @@ -64,6 +64,7 @@ typedef enum { RELOC_AARCH64_B_COND, RELOC_AARCH64_B_COND_ABS, RELOC_AARCH64_CB, + RELOC_AARCH64_TB } RELOC_TYPE; static_assert(sizeof(RELOC_TYPE) == 4, "RELOC_TYPE must be 32 bit"); diff --git a/cmake/toolchain/cflags/coverage.cmake b/cmake/toolchain/cflags/coverage.cmake index c760818..861049b 100644 --- a/cmake/toolchain/cflags/coverage.cmake +++ b/cmake/toolchain/cflags/coverage.cmake @@ -32,6 +32,11 @@ elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" ST if (NOT WIN32) append_cflags(COVERAGE_CFLAGS "-fprofile-instr-generate -fcoverage-mapping") endif () + if ("${CMAKE_XCODE_BUILD_SYSTEM}" STREQUAL "12") + # Problem detected with xcode 12, maybe some other versions also contain + # Xcode doesn't link coverage library without this parameter + string(APPEND _LINKER_FLAGS " --coverage") + endif () endif () append_cflags(COVERAGE_CFLAGS -fno-omit-frame-pointer)