| 246 | //------------------------------------------------------------------------- |
| 247 | |
| 248 | static bool __fix_loadlit(instruction inpp, instruction outpp, context *ctxp) { |
| 249 | const uint32_t ins = *(*inpp); |
| 250 | |
| 251 | // memory prefetch("prfm"), just skip it |
| 252 | // http://infocenter.arm.com/help/topic/com.arm.doc.100069_0608_00_en/pge1427897420050.html |
| 253 | if ((ins & 0xff000000u) == 0xd8000000u) { |
| 254 | ctxp->process_fix_map(ctxp->get_and_set_current_index(*inpp, *outpp)); |
| 255 | ++(*inpp); |
| 256 | return true; |
| 257 | } //if |
| 258 | |
| 259 | constexpr uint32_t msb = 8u; |
| 260 | constexpr uint32_t lsb = 5u; |
| 261 | constexpr uint32_t mask_30 = 0x40000000u; // 0b01000000000000000000000000000000 |
| 262 | constexpr uint32_t mask_31 = 0x80000000u; // 0b10000000000000000000000000000000 |
| 263 | constexpr uint32_t lmask = 0xff00001fu; // 0b11111111000000000000000000011111 |
| 264 | constexpr uint32_t mask_ldr = 0xbf000000u; // 0b10111111000000000000000000000000 |
| 265 | constexpr uint32_t op_ldr = 0x18000000u; // 0b00011000000000000000000000000000 "LDR Wt/Xt, label" | ADDR_PCREL19 |
| 266 | constexpr uint32_t mask_ldrv = 0x3f000000u; // 0b00111111000000000000000000000000 |
| 267 | constexpr uint32_t op_ldrv = 0x1c000000u; // 0b00011100000000000000000000000000 "LDR St/Dt/Qt, label" | ADDR_PCREL19 |
| 268 | constexpr uint32_t mask_ldrsw = 0xff000000u; // 0b11111111000000000000000000000000 |
| 269 | constexpr uint32_t op_ldrsw = 0x98000000u; // "LDRSW Xt, label" | ADDR_PCREL19 | load register signed word |
| 270 | // LDR S0, #0 | 0b00011100000000000000000000000000 | 32-bit |
| 271 | // LDR D0, #0 | 0b01011100000000000000000000000000 | 64-bit |
| 272 | // LDR Q0, #0 | 0b10011100000000000000000000000000 | 128-bit |
| 273 | // INVALID | 0b11011100000000000000000000000000 | may be 256-bit |
| 274 | |
| 275 | uint32_t mask = mask_ldr; |
| 276 | uintptr_t faligned = (ins & mask_30) ? 7u : 3u; |
| 277 | if ((ins & mask_ldr) != op_ldr) { |
| 278 | mask = mask_ldrv; |
| 279 | if (faligned != 7u) |
| 280 | faligned = (ins & mask_31) ? 15u : 3u; |
| 281 | if ((ins & mask_ldrv) != op_ldrv) { |
| 282 | if ((ins & mask_ldrsw) != op_ldrsw) { |
| 283 | return false; |
| 284 | } //if |
| 285 | mask = mask_ldrsw; |
| 286 | faligned = 7u; |
| 287 | } //if |
| 288 | } //if |
| 289 | |
| 290 | intptr_t current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); |
| 291 | int64_t absolute_addr = reinterpret_cast<int64_t>(*inpp) + |
| 292 | ((static_cast<int32_t>(ins << msb) >> (msb + lsb - 2u)) & ~3u); |
| 293 | int64_t new_pc_offset = |
| 294 | static_cast<int64_t>(absolute_addr - reinterpret_cast<int64_t>(*outpp)) >> 2; // shifted |
| 295 | bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); |
| 296 | // special_fix_type may encounter issue when there are mixed data and code |
| 297 | if (special_fix_type || (llabs(new_pc_offset) + (faligned + 1u - 4u)) > (~lmask >> lsb)) { |
| 298 | while ((reinterpret_cast<uint64_t>(*outpp + 2) & faligned) != 0u) { |
| 299 | *(*outpp)++ = A64_NOP; |
| 300 | } |
| 301 | ctxp->reset_current_ins(current_idx, *outpp); |
| 302 | |
| 303 | // Note that if memory at absolute_addr is writeable (non-const), we will fail to fetch it. |
| 304 | // And what's worse, we may unexpectedly overwrite something if special_fix_type is true... |
| 305 | uint32_t ns = static_cast<uint32_t>((faligned + 1) / sizeof(uint32_t)); |
no outgoing calls
no test coverage detected