Commit 46152182100e68f7f8aa4954af1bf91160bb3d15
1 parent
f3a9676a
Rewrite Arm host support.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2071 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
6 changed files
with
295 additions
and
78 deletions
arm.ld
... | ... | @@ -53,6 +53,10 @@ SECTIONS |
53 | 53 | .fini : { *(.fini) } =0x47ff041f |
54 | 54 | .rodata : { *(.rodata) *(.gnu.linkonce.r*) } |
55 | 55 | .rodata1 : { *(.rodata1) } |
56 | + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } | |
57 | + __exidx_start = .; | |
58 | + .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } | |
59 | + __exidx_end = .; | |
56 | 60 | .reginfo : { *(.reginfo) } |
57 | 61 | /* Adjust the address for the data segment. We want to adjust up to |
58 | 62 | the same address within the page on the next page up. */ |
... | ... | @@ -63,7 +67,28 @@ SECTIONS |
63 | 67 | *(.gnu.linkonce.d*) |
64 | 68 | CONSTRUCTORS |
65 | 69 | } |
70 | + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } | |
66 | 71 | .data1 : { *(.data1) } |
72 | + .preinit_array : | |
73 | + { | |
74 | + PROVIDE_HIDDEN (__preinit_array_start = .); | |
75 | + KEEP (*(.preinit_array)) | |
76 | + PROVIDE_HIDDEN (__preinit_array_end = .); | |
77 | + } | |
78 | + .init_array : | |
79 | + { | |
80 | + PROVIDE_HIDDEN (__init_array_start = .); | |
81 | + KEEP (*(SORT(.init_array.*))) | |
82 | + KEEP (*(.init_array)) | |
83 | + PROVIDE_HIDDEN (__init_array_end = .); | |
84 | + } | |
85 | + .fini_array : | |
86 | + { | |
87 | + PROVIDE_HIDDEN (__fini_array_start = .); | |
88 | + KEEP (*(.fini_array)) | |
89 | + KEEP (*(SORT(.fini_array.*))) | |
90 | + PROVIDE_HIDDEN (__fini_array_end = .); | |
91 | + } | |
67 | 92 | .ctors : |
68 | 93 | { |
69 | 94 | *(.ctors) | ... | ... |
cpu-all.h
... | ... | @@ -992,6 +992,15 @@ static inline int64_t cpu_get_real_ticks (void) |
992 | 992 | return rval.i64; |
993 | 993 | #endif |
994 | 994 | } |
995 | +#else | |
996 | +/* The host CPU doesn't have an easily accessible cycle counter. | |
997 | + Just return a monotonically increasing vlue. This will be totally wrong, | |
998 | + but hopefully better than nothing. */ | |
999 | +static inline int64_t cpu_get_real_ticks (void) | |
1000 | +{ | |
1001 | + static int64_t ticks = 0; | |
1002 | + return ticks++; | |
1003 | +} | |
995 | 1004 | #endif |
996 | 1005 | |
997 | 1006 | /* profiling */ | ... | ... |
disas.c
... | ... | @@ -271,11 +271,9 @@ void disas(FILE *out, void *code, unsigned long size) |
271 | 271 | for (pc = (unsigned long)code; pc < (unsigned long)code + size; pc += count) { |
272 | 272 | fprintf(out, "0x%08lx: ", pc); |
273 | 273 | #ifdef __arm__ |
274 | - /* since data are included in the code, it is better to | |
274 | + /* since data is included in the code, it is better to | |
275 | 275 | display code data too */ |
276 | - if (is_host) { | |
277 | - fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc)); | |
278 | - } | |
276 | + fprintf(out, "%08x ", (int)bfd_getl32((const bfd_byte *)pc)); | |
279 | 277 | #endif |
280 | 278 | count = print_insn(pc, &disasm_info); |
281 | 279 | fprintf(out, "\n"); | ... | ... |
dyngen.c
... | ... | @@ -1255,90 +1255,149 @@ int arm_emit_ldr_info(const char *name, unsigned long start_offset, |
1255 | 1255 | { |
1256 | 1256 | uint8_t *p; |
1257 | 1257 | uint32_t insn; |
1258 | - int offset, min_offset, pc_offset, data_size; | |
1258 | + int offset, min_offset, pc_offset, data_size, spare, max_pool; | |
1259 | 1259 | uint8_t data_allocated[1024]; |
1260 | 1260 | unsigned int data_index; |
1261 | + int type; | |
1261 | 1262 | |
1262 | 1263 | memset(data_allocated, 0, sizeof(data_allocated)); |
1263 | 1264 | |
1264 | 1265 | p = p_start; |
1265 | 1266 | min_offset = p_end - p_start; |
1267 | + spare = 0x7fffffff; | |
1266 | 1268 | while (p < p_start + min_offset) { |
1267 | 1269 | insn = get32((uint32_t *)p); |
1270 | + /* TODO: Armv5e ldrd. */ | |
1271 | + /* TODO: VFP load. */ | |
1268 | 1272 | if ((insn & 0x0d5f0000) == 0x051f0000) { |
1269 | 1273 | /* ldr reg, [pc, #im] */ |
1270 | 1274 | offset = insn & 0xfff; |
1271 | 1275 | if (!(insn & 0x00800000)) |
1272 | - offset = -offset; | |
1276 | + offset = -offset; | |
1277 | + max_pool = 4096; | |
1278 | + type = 0; | |
1279 | + } else if ((insn & 0x0e5f0f00) == 0x0c1f0100) { | |
1280 | + /* FPA ldf. */ | |
1281 | + offset = (insn & 0xff) << 2; | |
1282 | + if (!(insn & 0x00800000)) | |
1283 | + offset = -offset; | |
1284 | + max_pool = 1024; | |
1285 | + type = 1; | |
1286 | + } else if ((insn & 0x0fff0000) == 0x028f0000) { | |
1287 | + /* Some gcc load a doubleword immediate with | |
1288 | + add regN, pc, #imm | |
1289 | + ldmia regN, {regN, regM} | |
1290 | + Hope and pray the compiler never generates somethin like | |
1291 | + add reg, pc, #imm1; ldr reg, [reg, #-imm2]; */ | |
1292 | + int r; | |
1293 | + | |
1294 | + r = (insn & 0xf00) >> 7; | |
1295 | + offset = ((insn & 0xff) >> r) | ((insn & 0xff) << (32 - r)); | |
1296 | + max_pool = 1024; | |
1297 | + type = 2; | |
1298 | + } else { | |
1299 | + max_pool = 0; | |
1300 | + type = -1; | |
1301 | + } | |
1302 | + if (type >= 0) { | |
1303 | + /* PC-relative load needs fixing up. */ | |
1304 | + if (spare > max_pool - offset) | |
1305 | + spare = max_pool - offset; | |
1273 | 1306 | if ((offset & 3) !=0) |
1274 | - error("%s:%04x: ldr pc offset must be 32 bit aligned", | |
1307 | + error("%s:%04x: pc offset must be 32 bit aligned", | |
1308 | + name, start_offset + p - p_start); | |
1309 | + if (offset < 0) | |
1310 | + error("%s:%04x: Embedded literal value", | |
1275 | 1311 | name, start_offset + p - p_start); |
1276 | 1312 | pc_offset = p - p_start + offset + 8; |
1277 | 1313 | if (pc_offset <= (p - p_start) || |
1278 | 1314 | pc_offset >= (p_end - p_start)) |
1279 | - error("%s:%04x: ldr pc offset must point inside the function code", | |
1315 | + error("%s:%04x: pc offset must point inside the function code", | |
1280 | 1316 | name, start_offset + p - p_start); |
1281 | 1317 | if (pc_offset < min_offset) |
1282 | 1318 | min_offset = pc_offset; |
1283 | 1319 | if (outfile) { |
1284 | - /* ldr position */ | |
1320 | + /* The intruction position */ | |
1285 | 1321 | fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n", |
1286 | 1322 | p - p_start); |
1287 | - /* ldr data index */ | |
1288 | - data_index = ((p_end - p_start) - pc_offset - 4) >> 2; | |
1289 | - fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr + %d;\n", | |
1323 | + /* The position of the constant pool data. */ | |
1324 | + data_index = ((p_end - p_start) - pc_offset) >> 2; | |
1325 | + fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr - %d;\n", | |
1290 | 1326 | data_index); |
1327 | + fprintf(outfile, " arm_ldr_ptr->type = %d;\n", type); | |
1291 | 1328 | fprintf(outfile, " arm_ldr_ptr++;\n"); |
1292 | - if (data_index >= sizeof(data_allocated)) | |
1293 | - error("%s: too many data", name); | |
1294 | - if (!data_allocated[data_index]) { | |
1295 | - ELF_RELOC *rel; | |
1296 | - int i, addend, type; | |
1297 | - const char *sym_name, *p; | |
1298 | - char relname[1024]; | |
1299 | - | |
1300 | - data_allocated[data_index] = 1; | |
1301 | - | |
1302 | - /* data value */ | |
1303 | - addend = get32((uint32_t *)(p_start + pc_offset)); | |
1304 | - relname[0] = '\0'; | |
1305 | - for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { | |
1306 | - if (rel->r_offset == (pc_offset + start_offset)) { | |
1307 | - sym_name = get_rel_sym_name(rel); | |
1308 | - /* the compiler leave some unnecessary references to the code */ | |
1309 | - get_reloc_expr(relname, sizeof(relname), sym_name); | |
1310 | - type = ELF32_R_TYPE(rel->r_info); | |
1311 | - if (type != R_ARM_ABS32) | |
1312 | - error("%s: unsupported data relocation", name); | |
1313 | - break; | |
1314 | - } | |
1315 | - } | |
1316 | - fprintf(outfile, " arm_data_ptr[%d] = 0x%x", | |
1317 | - data_index, addend); | |
1318 | - if (relname[0] != '\0') | |
1319 | - fprintf(outfile, " + %s", relname); | |
1320 | - fprintf(outfile, ";\n"); | |
1321 | - } | |
1322 | 1329 | } |
1323 | 1330 | } |
1324 | 1331 | p += 4; |
1325 | 1332 | } |
1333 | + | |
1334 | + /* Copy and relocate the constant pool data. */ | |
1326 | 1335 | data_size = (p_end - p_start) - min_offset; |
1327 | 1336 | if (data_size > 0 && outfile) { |
1328 | - fprintf(outfile, " arm_data_ptr += %d;\n", data_size >> 2); | |
1337 | + spare += min_offset; | |
1338 | + fprintf(outfile, " arm_data_ptr -= %d;\n", data_size >> 2); | |
1339 | + fprintf(outfile, " arm_pool_ptr -= %d;\n", data_size); | |
1340 | + fprintf(outfile, " if (arm_pool_ptr > gen_code_ptr + %d)\n" | |
1341 | + " arm_pool_ptr = gen_code_ptr + %d;\n", | |
1342 | + spare, spare); | |
1343 | + | |
1344 | + data_index = 0; | |
1345 | + for (pc_offset = min_offset; | |
1346 | + pc_offset < p_end - p_start; | |
1347 | + pc_offset += 4) { | |
1348 | + | |
1349 | + ELF_RELOC *rel; | |
1350 | + int i, addend, type; | |
1351 | + const char *sym_name; | |
1352 | + char relname[1024]; | |
1353 | + | |
1354 | + /* data value */ | |
1355 | + addend = get32((uint32_t *)(p_start + pc_offset)); | |
1356 | + relname[0] = '\0'; | |
1357 | + for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { | |
1358 | + if (rel->r_offset == (pc_offset + start_offset)) { | |
1359 | + sym_name = get_rel_sym_name(rel); | |
1360 | + /* the compiler leave some unnecessary references to the code */ | |
1361 | + get_reloc_expr(relname, sizeof(relname), sym_name); | |
1362 | + type = ELF32_R_TYPE(rel->r_info); | |
1363 | + if (type != R_ARM_ABS32) | |
1364 | + error("%s: unsupported data relocation", name); | |
1365 | + break; | |
1366 | + } | |
1367 | + } | |
1368 | + fprintf(outfile, " arm_data_ptr[%d] = 0x%x", | |
1369 | + data_index, addend); | |
1370 | + if (relname[0] != '\0') | |
1371 | + fprintf(outfile, " + %s", relname); | |
1372 | + fprintf(outfile, ";\n"); | |
1373 | + | |
1374 | + data_index++; | |
1375 | + } | |
1329 | 1376 | } |
1330 | 1377 | |
1331 | - /* the last instruction must be a mov pc, lr */ | |
1332 | 1378 | if (p == p_start) |
1333 | 1379 | goto arm_ret_error; |
1334 | 1380 | p -= 4; |
1335 | 1381 | insn = get32((uint32_t *)p); |
1336 | - if ((insn & 0xffff0000) != 0xe91b0000) { | |
1382 | + /* The last instruction must be an ldm instruction. There are several | |
1383 | + forms generated by gcc: | |
1384 | + ldmib sp, {..., pc} (implies a sp adjustment of +4) | |
1385 | + ldmia sp, {..., pc} | |
1386 | + ldmea fp, {..., pc} */ | |
1387 | + if ((insn & 0xffff8000) == 0xe99d8000) { | |
1388 | + if (outfile) { | |
1389 | + fprintf(outfile, | |
1390 | + " *(uint32_t *)(gen_code_ptr + %d) = 0xe28dd004;\n", | |
1391 | + p - p_start); | |
1392 | + } | |
1393 | + p += 4; | |
1394 | + } else if ((insn & 0xffff8000) != 0xe89d8000 | |
1395 | + && (insn & 0xffff8000) != 0xe91b8000) { | |
1337 | 1396 | arm_ret_error: |
1338 | 1397 | if (!outfile) |
1339 | 1398 | printf("%s: invalid epilog\n", name); |
1340 | 1399 | } |
1341 | - return p - p_start; | |
1400 | + return p - p_start; | |
1342 | 1401 | } |
1343 | 1402 | #endif |
1344 | 1403 | |
... | ... | @@ -1537,6 +1596,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, |
1537 | 1596 | } |
1538 | 1597 | #elif defined(HOST_ARM) |
1539 | 1598 | { |
1599 | + uint32_t insn; | |
1600 | + | |
1540 | 1601 | if ((p_end - p_start) <= 16) |
1541 | 1602 | error("%s: function too small", name); |
1542 | 1603 | if (get32((uint32_t *)p_start) != 0xe1a0c00d || |
... | ... | @@ -1545,6 +1606,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, |
1545 | 1606 | error("%s: invalid prolog", name); |
1546 | 1607 | p_start += 12; |
1547 | 1608 | start_offset += 12; |
1609 | + insn = get32((uint32_t *)p_start); | |
1610 | + if ((insn & 0xffffff00) == 0xe24dd000) { | |
1611 | + /* Stack adjustment. Assume op uses the frame pointer. */ | |
1612 | + p_start -= 4; | |
1613 | + start_offset -= 4; | |
1614 | + } | |
1548 | 1615 | copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end, |
1549 | 1616 | relocs, nb_relocs); |
1550 | 1617 | } |
... | ... | @@ -2282,7 +2349,37 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, |
2282 | 2349 | int type; |
2283 | 2350 | int addend; |
2284 | 2351 | int reloc_offset; |
2285 | - | |
2352 | + uint32_t insn; | |
2353 | + | |
2354 | + insn = get32((uint32_t *)(p_start + 4)); | |
2355 | + /* If prologue ends in sub sp, sp, #const then assume | |
2356 | + op has a stack frame and needs the frame pointer. */ | |
2357 | + if ((insn & 0xffffff00) == 0xe24dd000) { | |
2358 | + int i; | |
2359 | + uint32_t opcode; | |
2360 | + opcode = 0xe28db000; /* add fp, sp, #0. */ | |
2361 | +#if 0 | |
2362 | +/* ??? Need to undo the extra stack adjustment at the end of the op. | |
2363 | + For now just leave the stack misaligned and hope it doesn't break anything | |
2364 | + too important. */ | |
2365 | + if ((insn & 4) != 0) { | |
2366 | + /* Preserve doubleword stack alignment. */ | |
2367 | + fprintf(outfile, | |
2368 | + " *(uint32_t *)(gen_code_ptr + 4)= 0x%x;\n", | |
2369 | + insn + 4); | |
2370 | + opcode -= 4; | |
2371 | + } | |
2372 | +#endif | |
2373 | + insn = get32((uint32_t *)(p_start - 4)); | |
2374 | + /* Calculate the size of the saved registers, | |
2375 | + excluding pc. */ | |
2376 | + for (i = 0; i < 15; i++) { | |
2377 | + if (insn & (1 << i)) | |
2378 | + opcode += 4; | |
2379 | + } | |
2380 | + fprintf(outfile, | |
2381 | + " *(uint32_t *)gen_code_ptr = 0x%x;\n", opcode); | |
2382 | + } | |
2286 | 2383 | arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end, |
2287 | 2384 | relocs, nb_relocs); |
2288 | 2385 | |
... | ... | @@ -2303,6 +2400,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, |
2303 | 2400 | reloc_offset, name, addend); |
2304 | 2401 | break; |
2305 | 2402 | case R_ARM_PC24: |
2403 | + case R_ARM_JUMP24: | |
2404 | + case R_ARM_CALL: | |
2306 | 2405 | fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n", |
2307 | 2406 | reloc_offset, addend, name); |
2308 | 2407 | break; |
... | ... | @@ -2407,6 +2506,28 @@ int gen_file(FILE *outfile, int out_type) |
2407 | 2506 | |
2408 | 2507 | } else { |
2409 | 2508 | /* generate big code generation switch */ |
2509 | + | |
2510 | +#ifdef HOST_ARM | |
2511 | + /* We need to know the size of all the ops so we can figure out when | |
2512 | + to emit constant pools. This must be consistent with opc.h. */ | |
2513 | +fprintf(outfile, | |
2514 | +"static const uint32_t arm_opc_size[] = {\n" | |
2515 | +" 0,\n" /* end */ | |
2516 | +" 0,\n" /* nop */ | |
2517 | +" 0,\n" /* nop1 */ | |
2518 | +" 0,\n" /* nop2 */ | |
2519 | +" 0,\n"); /* nop3 */ | |
2520 | + for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { | |
2521 | + const char *name; | |
2522 | + name = get_sym_name(sym); | |
2523 | + if (strstart(name, OP_PREFIX, NULL)) { | |
2524 | + fprintf(outfile, " %d,\n", sym->st_size); | |
2525 | + } | |
2526 | + } | |
2527 | +fprintf(outfile, | |
2528 | +"};\n"); | |
2529 | +#endif | |
2530 | + | |
2410 | 2531 | fprintf(outfile, |
2411 | 2532 | "int dyngen_code(uint8_t *gen_code_buf,\n" |
2412 | 2533 | " uint16_t *label_offsets, uint16_t *jmp_offsets,\n" |
... | ... | @@ -2417,10 +2538,36 @@ fprintf(outfile, |
2417 | 2538 | " const uint32_t *opparam_ptr;\n"); |
2418 | 2539 | |
2419 | 2540 | #ifdef HOST_ARM |
2541 | +/* Arm is tricky because it uses constant pools for loading immediate values. | |
2542 | + We assume (and require) each function is code followed by a constant pool. | |
2543 | + All the ops are small so this should be ok. For each op we figure | |
2544 | + out how much "spare" range we have in the load instructions. This allows | |
2545 | + us to insert subsequent ops in between the op and the constant pool, | |
2546 | + eliminating the neeed to jump around the pool. | |
2547 | + | |
2548 | + We currently generate: | |
2549 | + | |
2550 | + [ For this example we assume merging would move op1_pool out of range. | |
2551 | + In practice we should be able to combine many ops before the offset | |
2552 | + limits are reached. ] | |
2553 | + op1_code; | |
2554 | + op2_code; | |
2555 | + goto op3; | |
2556 | + op2_pool; | |
2557 | + op1_pool; | |
2558 | +op3: | |
2559 | + op3_code; | |
2560 | + ret; | |
2561 | + op3_pool; | |
2562 | + | |
2563 | + Ideally we'd put op1_pool before op2_pool, but that requires two passes. | |
2564 | + */ | |
2420 | 2565 | fprintf(outfile, |
2421 | 2566 | " uint8_t *last_gen_code_ptr = gen_code_buf;\n" |
2422 | 2567 | " LDREntry *arm_ldr_ptr = arm_ldr_table;\n" |
2423 | -" uint32_t *arm_data_ptr = arm_data_table;\n"); | |
2568 | +" uint32_t *arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n" | |
2569 | +/* Initialise the parmissible pool offset to an arbitary large value. */ | |
2570 | +" uint8_t *arm_pool_ptr = gen_code_buf + 0x1000000;\n"); | |
2424 | 2571 | #endif |
2425 | 2572 | #ifdef HOST_IA64 |
2426 | 2573 | { |
... | ... | @@ -2489,9 +2636,23 @@ fprintf(outfile, |
2489 | 2636 | /* Generate prologue, if needed. */ |
2490 | 2637 | |
2491 | 2638 | fprintf(outfile, |
2492 | -" for(;;) {\n" | |
2493 | -" switch(*opc_ptr++) {\n" | |
2494 | -); | |
2639 | +" for(;;) {\n"); | |
2640 | + | |
2641 | +#ifdef HOST_ARM | |
2642 | +/* Generate constant pool if needed */ | |
2643 | +fprintf(outfile, | |
2644 | +" if (gen_code_ptr + arm_opc_size[*opc_ptr] >= arm_pool_ptr) {\n" | |
2645 | +" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, " | |
2646 | +"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 1);\n" | |
2647 | +" last_gen_code_ptr = gen_code_ptr;\n" | |
2648 | +" arm_ldr_ptr = arm_ldr_table;\n" | |
2649 | +" arm_data_ptr = arm_data_table + ARM_LDR_TABLE_SIZE;\n" | |
2650 | +" arm_pool_ptr = gen_code_ptr + 0x1000000;\n" | |
2651 | +" }\n"); | |
2652 | +#endif | |
2653 | + | |
2654 | +fprintf(outfile, | |
2655 | +" switch(*opc_ptr++) {\n"); | |
2495 | 2656 | |
2496 | 2657 | for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { |
2497 | 2658 | const char *name; |
... | ... | @@ -2525,17 +2686,6 @@ fprintf(outfile, |
2525 | 2686 | " goto the_end;\n" |
2526 | 2687 | " }\n"); |
2527 | 2688 | |
2528 | -#ifdef HOST_ARM | |
2529 | -/* generate constant table if needed */ | |
2530 | -fprintf(outfile, | |
2531 | -" if ((gen_code_ptr - last_gen_code_ptr) >= (MAX_FRAG_SIZE - MAX_OP_SIZE)) {\n" | |
2532 | -" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 1);\n" | |
2533 | -" last_gen_code_ptr = gen_code_ptr;\n" | |
2534 | -" arm_ldr_ptr = arm_ldr_table;\n" | |
2535 | -" arm_data_ptr = arm_data_table;\n" | |
2536 | -" }\n"); | |
2537 | -#endif | |
2538 | - | |
2539 | 2689 | |
2540 | 2690 | fprintf(outfile, |
2541 | 2691 | " }\n" |
... | ... | @@ -2553,7 +2703,10 @@ fprintf(outfile, |
2553 | 2703 | |
2554 | 2704 | /* generate some code patching */ |
2555 | 2705 | #ifdef HOST_ARM |
2556 | -fprintf(outfile, "gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 0);\n"); | |
2706 | +fprintf(outfile, | |
2707 | +"if (arm_data_ptr != arm_data_table + ARM_LDR_TABLE_SIZE)\n" | |
2708 | +" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, " | |
2709 | +"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 0);\n"); | |
2557 | 2710 | #endif |
2558 | 2711 | /* flush instruction cache */ |
2559 | 2712 | fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n"); | ... | ... |
dyngen.h
... | ... | @@ -19,7 +19,7 @@ |
19 | 19 | */ |
20 | 20 | |
21 | 21 | int __op_param1, __op_param2, __op_param3; |
22 | -#ifdef __sparc__ | |
22 | +#if defined(__sparc__) || defined(__arm__) | |
23 | 23 | void __op_gen_label1(){} |
24 | 24 | void __op_gen_label2(){} |
25 | 25 | void __op_gen_label3(){} |
... | ... | @@ -145,18 +145,16 @@ void fix_bsr(void *p, int offset) { |
145 | 145 | |
146 | 146 | #ifdef __arm__ |
147 | 147 | |
148 | -#define MAX_OP_SIZE (128 * 4) /* in bytes */ | |
149 | -/* max size of the code that can be generated without calling arm_flush_ldr */ | |
150 | -#define MAX_FRAG_SIZE (1024 * 4) | |
151 | -//#define MAX_FRAG_SIZE (135 * 4) /* for testing */ | |
148 | +#define ARM_LDR_TABLE_SIZE 1024 | |
152 | 149 | |
153 | 150 | typedef struct LDREntry { |
154 | 151 | uint8_t *ptr; |
155 | 152 | uint32_t *data_ptr; |
153 | + unsigned type:2; | |
156 | 154 | } LDREntry; |
157 | 155 | |
158 | 156 | static LDREntry arm_ldr_table[1024]; |
159 | -static uint32_t arm_data_table[1024]; | |
157 | +static uint32_t arm_data_table[ARM_LDR_TABLE_SIZE]; | |
160 | 158 | |
161 | 159 | extern char exec_loop; |
162 | 160 | |
... | ... | @@ -175,8 +173,9 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr, |
175 | 173 | int offset, data_size, target; |
176 | 174 | uint8_t *data_ptr; |
177 | 175 | uint32_t insn; |
176 | + uint32_t mask; | |
178 | 177 | |
179 | - data_size = (uint8_t *)data_end - (uint8_t *)data_start; | |
178 | + data_size = (data_end - data_start) << 2; | |
180 | 179 | |
181 | 180 | if (gen_jmp) { |
182 | 181 | /* generate branch to skip the data */ |
... | ... | @@ -198,17 +197,48 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr, |
198 | 197 | offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) + |
199 | 198 | (unsigned long)data_ptr - |
200 | 199 | (unsigned long)ptr - 8; |
201 | - insn = *ptr & ~(0xfff | 0x00800000); | |
202 | 200 | if (offset < 0) { |
203 | - offset = - offset; | |
204 | - } else { | |
205 | - insn |= 0x00800000; | |
206 | - } | |
207 | - if (offset > 0xfff) { | |
208 | - fprintf(stderr, "Error ldr offset\n"); | |
201 | + fprintf(stderr, "Negative constant pool offset\n"); | |
209 | 202 | abort(); |
210 | 203 | } |
211 | - insn |= offset; | |
204 | + switch (le->type) { | |
205 | + case 0: /* ldr */ | |
206 | + mask = ~0x00800fff; | |
207 | + if (offset >= 4096) { | |
208 | + fprintf(stderr, "Bad ldr offset\n"); | |
209 | + abort(); | |
210 | + } | |
211 | + break; | |
212 | + case 1: /* ldc */ | |
213 | + mask = ~0x008000ff; | |
214 | + if (offset >= 1024 ) { | |
215 | + fprintf(stderr, "Bad ldc offset\n"); | |
216 | + abort(); | |
217 | + } | |
218 | + break; | |
219 | + case 2: /* add */ | |
220 | + mask = ~0xfff; | |
221 | + if (offset >= 1024 ) { | |
222 | + fprintf(stderr, "Bad add offset\n"); | |
223 | + abort(); | |
224 | + } | |
225 | + break; | |
226 | + default: | |
227 | + fprintf(stderr, "Bad pc relative fixup\n"); | |
228 | + abort(); | |
229 | + } | |
230 | + insn = *ptr & mask; | |
231 | + switch (le->type) { | |
232 | + case 0: /* ldr */ | |
233 | + insn |= offset | 0x00800000; | |
234 | + break; | |
235 | + case 1: /* ldc */ | |
236 | + insn |= (offset >> 2) | 0x00800000; | |
237 | + break; | |
238 | + case 2: /* add */ | |
239 | + insn |= (offset >> 2) | 0xf00; | |
240 | + break; | |
241 | + } | |
212 | 242 | *ptr = insn; |
213 | 243 | } |
214 | 244 | return gen_code_ptr; | ... | ... |
elf.h
... | ... | @@ -502,6 +502,8 @@ typedef struct { |
502 | 502 | #define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ |
503 | 503 | #define R_ARM_GOT32 26 /* 32 bit GOT entry */ |
504 | 504 | #define R_ARM_PLT32 27 /* 32 bit PLT address */ |
505 | +#define R_ARM_CALL 28 | |
506 | +#define R_ARM_JUMP24 29 | |
505 | 507 | #define R_ARM_GNU_VTENTRY 100 |
506 | 508 | #define R_ARM_GNU_VTINHERIT 101 |
507 | 509 | #define R_ARM_THM_PC11 102 /* thumb unconditional branch */ | ... | ... |