Commit 46152182100e68f7f8aa4954af1bf91160bb3d15

Authored by pbrook
1 parent f3a9676a

Rewrite Arm host support.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2071 c046a42c-6fe2-441c-8c8c-71466251a162
@@ -53,6 +53,10 @@ SECTIONS @@ -53,6 +53,10 @@ SECTIONS
53 .fini : { *(.fini) } =0x47ff041f 53 .fini : { *(.fini) } =0x47ff041f
54 .rodata : { *(.rodata) *(.gnu.linkonce.r*) } 54 .rodata : { *(.rodata) *(.gnu.linkonce.r*) }
55 .rodata1 : { *(.rodata1) } 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 .reginfo : { *(.reginfo) } 60 .reginfo : { *(.reginfo) }
57 /* Adjust the address for the data segment. We want to adjust up to 61 /* Adjust the address for the data segment. We want to adjust up to
58 the same address within the page on the next page up. */ 62 the same address within the page on the next page up. */
@@ -63,7 +67,28 @@ SECTIONS @@ -63,7 +67,28 @@ SECTIONS
63 *(.gnu.linkonce.d*) 67 *(.gnu.linkonce.d*)
64 CONSTRUCTORS 68 CONSTRUCTORS
65 } 69 }
  70 + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
66 .data1 : { *(.data1) } 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 .ctors : 92 .ctors :
68 { 93 {
69 *(.ctors) 94 *(.ctors)
cpu-all.h
@@ -992,6 +992,15 @@ static inline int64_t cpu_get_real_ticks (void) @@ -992,6 +992,15 @@ static inline int64_t cpu_get_real_ticks (void)
992 return rval.i64; 992 return rval.i64;
993 #endif 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 #endif 1004 #endif
996 1005
997 /* profiling */ 1006 /* profiling */
@@ -271,11 +271,9 @@ void disas(FILE *out, void *code, unsigned long size) @@ -271,11 +271,9 @@ void disas(FILE *out, void *code, unsigned long size)
271 for (pc = (unsigned long)code; pc < (unsigned long)code + size; pc += count) { 271 for (pc = (unsigned long)code; pc < (unsigned long)code + size; pc += count) {
272 fprintf(out, "0x%08lx: ", pc); 272 fprintf(out, "0x%08lx: ", pc);
273 #ifdef __arm__ 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 display code data too */ 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 #endif 277 #endif
280 count = print_insn(pc, &disasm_info); 278 count = print_insn(pc, &disasm_info);
281 fprintf(out, "\n"); 279 fprintf(out, "\n");
dyngen.c
@@ -1255,90 +1255,149 @@ int arm_emit_ldr_info(const char *name, unsigned long start_offset, @@ -1255,90 +1255,149 @@ int arm_emit_ldr_info(const char *name, unsigned long start_offset,
1255 { 1255 {
1256 uint8_t *p; 1256 uint8_t *p;
1257 uint32_t insn; 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 uint8_t data_allocated[1024]; 1259 uint8_t data_allocated[1024];
1260 unsigned int data_index; 1260 unsigned int data_index;
  1261 + int type;
1261 1262
1262 memset(data_allocated, 0, sizeof(data_allocated)); 1263 memset(data_allocated, 0, sizeof(data_allocated));
1263 1264
1264 p = p_start; 1265 p = p_start;
1265 min_offset = p_end - p_start; 1266 min_offset = p_end - p_start;
  1267 + spare = 0x7fffffff;
1266 while (p < p_start + min_offset) { 1268 while (p < p_start + min_offset) {
1267 insn = get32((uint32_t *)p); 1269 insn = get32((uint32_t *)p);
  1270 + /* TODO: Armv5e ldrd. */
  1271 + /* TODO: VFP load. */
1268 if ((insn & 0x0d5f0000) == 0x051f0000) { 1272 if ((insn & 0x0d5f0000) == 0x051f0000) {
1269 /* ldr reg, [pc, #im] */ 1273 /* ldr reg, [pc, #im] */
1270 offset = insn & 0xfff; 1274 offset = insn & 0xfff;
1271 if (!(insn & 0x00800000)) 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 if ((offset & 3) !=0) 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 name, start_offset + p - p_start); 1311 name, start_offset + p - p_start);
1276 pc_offset = p - p_start + offset + 8; 1312 pc_offset = p - p_start + offset + 8;
1277 if (pc_offset <= (p - p_start) || 1313 if (pc_offset <= (p - p_start) ||
1278 pc_offset >= (p_end - p_start)) 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 name, start_offset + p - p_start); 1316 name, start_offset + p - p_start);
1281 if (pc_offset < min_offset) 1317 if (pc_offset < min_offset)
1282 min_offset = pc_offset; 1318 min_offset = pc_offset;
1283 if (outfile) { 1319 if (outfile) {
1284 - /* ldr position */ 1320 + /* The intruction position */
1285 fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n", 1321 fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n",
1286 p - p_start); 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 data_index); 1326 data_index);
  1327 + fprintf(outfile, " arm_ldr_ptr->type = %d;\n", type);
1291 fprintf(outfile, " arm_ldr_ptr++;\n"); 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 p += 4; 1331 p += 4;
1325 } 1332 }
  1333 +
  1334 + /* Copy and relocate the constant pool data. */
1326 data_size = (p_end - p_start) - min_offset; 1335 data_size = (p_end - p_start) - min_offset;
1327 if (data_size > 0 && outfile) { 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 if (p == p_start) 1378 if (p == p_start)
1333 goto arm_ret_error; 1379 goto arm_ret_error;
1334 p -= 4; 1380 p -= 4;
1335 insn = get32((uint32_t *)p); 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 arm_ret_error: 1396 arm_ret_error:
1338 if (!outfile) 1397 if (!outfile)
1339 printf("%s: invalid epilog\n", name); 1398 printf("%s: invalid epilog\n", name);
1340 } 1399 }
1341 - return p - p_start; 1400 + return p - p_start;
1342 } 1401 }
1343 #endif 1402 #endif
1344 1403
@@ -1537,6 +1596,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, @@ -1537,6 +1596,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
1537 } 1596 }
1538 #elif defined(HOST_ARM) 1597 #elif defined(HOST_ARM)
1539 { 1598 {
  1599 + uint32_t insn;
  1600 +
1540 if ((p_end - p_start) <= 16) 1601 if ((p_end - p_start) <= 16)
1541 error("%s: function too small", name); 1602 error("%s: function too small", name);
1542 if (get32((uint32_t *)p_start) != 0xe1a0c00d || 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,6 +1606,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
1545 error("%s: invalid prolog", name); 1606 error("%s: invalid prolog", name);
1546 p_start += 12; 1607 p_start += 12;
1547 start_offset += 12; 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 copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end, 1615 copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end,
1549 relocs, nb_relocs); 1616 relocs, nb_relocs);
1550 } 1617 }
@@ -2282,7 +2349,37 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, @@ -2282,7 +2349,37 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
2282 int type; 2349 int type;
2283 int addend; 2350 int addend;
2284 int reloc_offset; 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 arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end, 2383 arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end,
2287 relocs, nb_relocs); 2384 relocs, nb_relocs);
2288 2385
@@ -2303,6 +2400,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, @@ -2303,6 +2400,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
2303 reloc_offset, name, addend); 2400 reloc_offset, name, addend);
2304 break; 2401 break;
2305 case R_ARM_PC24: 2402 case R_ARM_PC24:
  2403 + case R_ARM_JUMP24:
  2404 + case R_ARM_CALL:
2306 fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n", 2405 fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n",
2307 reloc_offset, addend, name); 2406 reloc_offset, addend, name);
2308 break; 2407 break;
@@ -2407,6 +2506,28 @@ int gen_file(FILE *outfile, int out_type) @@ -2407,6 +2506,28 @@ int gen_file(FILE *outfile, int out_type)
2407 2506
2408 } else { 2507 } else {
2409 /* generate big code generation switch */ 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 fprintf(outfile, 2531 fprintf(outfile,
2411 "int dyngen_code(uint8_t *gen_code_buf,\n" 2532 "int dyngen_code(uint8_t *gen_code_buf,\n"
2412 " uint16_t *label_offsets, uint16_t *jmp_offsets,\n" 2533 " uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
@@ -2417,10 +2538,36 @@ fprintf(outfile, @@ -2417,10 +2538,36 @@ fprintf(outfile,
2417 " const uint32_t *opparam_ptr;\n"); 2538 " const uint32_t *opparam_ptr;\n");
2418 2539
2419 #ifdef HOST_ARM 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 fprintf(outfile, 2565 fprintf(outfile,
2421 " uint8_t *last_gen_code_ptr = gen_code_buf;\n" 2566 " uint8_t *last_gen_code_ptr = gen_code_buf;\n"
2422 " LDREntry *arm_ldr_ptr = arm_ldr_table;\n" 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 #endif 2571 #endif
2425 #ifdef HOST_IA64 2572 #ifdef HOST_IA64
2426 { 2573 {
@@ -2489,9 +2636,23 @@ fprintf(outfile, @@ -2489,9 +2636,23 @@ fprintf(outfile,
2489 /* Generate prologue, if needed. */ 2636 /* Generate prologue, if needed. */
2490 2637
2491 fprintf(outfile, 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 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { 2657 for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
2497 const char *name; 2658 const char *name;
@@ -2525,17 +2686,6 @@ fprintf(outfile, @@ -2525,17 +2686,6 @@ fprintf(outfile,
2525 " goto the_end;\n" 2686 " goto the_end;\n"
2526 " }\n"); 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 fprintf(outfile, 2690 fprintf(outfile,
2541 " }\n" 2691 " }\n"
@@ -2553,7 +2703,10 @@ fprintf(outfile, @@ -2553,7 +2703,10 @@ fprintf(outfile,
2553 2703
2554 /* generate some code patching */ 2704 /* generate some code patching */
2555 #ifdef HOST_ARM 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 #endif 2710 #endif
2558 /* flush instruction cache */ 2711 /* flush instruction cache */
2559 fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n"); 2712 fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");
dyngen.h
@@ -19,7 +19,7 @@ @@ -19,7 +19,7 @@
19 */ 19 */
20 20
21 int __op_param1, __op_param2, __op_param3; 21 int __op_param1, __op_param2, __op_param3;
22 -#ifdef __sparc__ 22 +#if defined(__sparc__) || defined(__arm__)
23 void __op_gen_label1(){} 23 void __op_gen_label1(){}
24 void __op_gen_label2(){} 24 void __op_gen_label2(){}
25 void __op_gen_label3(){} 25 void __op_gen_label3(){}
@@ -145,18 +145,16 @@ void fix_bsr(void *p, int offset) { @@ -145,18 +145,16 @@ void fix_bsr(void *p, int offset) {
145 145
146 #ifdef __arm__ 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 typedef struct LDREntry { 150 typedef struct LDREntry {
154 uint8_t *ptr; 151 uint8_t *ptr;
155 uint32_t *data_ptr; 152 uint32_t *data_ptr;
  153 + unsigned type:2;
156 } LDREntry; 154 } LDREntry;
157 155
158 static LDREntry arm_ldr_table[1024]; 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 extern char exec_loop; 159 extern char exec_loop;
162 160
@@ -175,8 +173,9 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr, @@ -175,8 +173,9 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
175 int offset, data_size, target; 173 int offset, data_size, target;
176 uint8_t *data_ptr; 174 uint8_t *data_ptr;
177 uint32_t insn; 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 if (gen_jmp) { 180 if (gen_jmp) {
182 /* generate branch to skip the data */ 181 /* generate branch to skip the data */
@@ -198,17 +197,48 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr, @@ -198,17 +197,48 @@ static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
198 offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) + 197 offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) +
199 (unsigned long)data_ptr - 198 (unsigned long)data_ptr -
200 (unsigned long)ptr - 8; 199 (unsigned long)ptr - 8;
201 - insn = *ptr & ~(0xfff | 0x00800000);  
202 if (offset < 0) { 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 abort(); 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 *ptr = insn; 242 *ptr = insn;
213 } 243 }
214 return gen_code_ptr; 244 return gen_code_ptr;
@@ -502,6 +502,8 @@ typedef struct { @@ -502,6 +502,8 @@ typedef struct {
502 #define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ 502 #define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */
503 #define R_ARM_GOT32 26 /* 32 bit GOT entry */ 503 #define R_ARM_GOT32 26 /* 32 bit GOT entry */
504 #define R_ARM_PLT32 27 /* 32 bit PLT address */ 504 #define R_ARM_PLT32 27 /* 32 bit PLT address */
  505 +#define R_ARM_CALL 28
  506 +#define R_ARM_JUMP24 29
505 #define R_ARM_GNU_VTENTRY 100 507 #define R_ARM_GNU_VTENTRY 100
506 #define R_ARM_GNU_VTINHERIT 101 508 #define R_ARM_GNU_VTINHERIT 101
507 #define R_ARM_THM_PC11 102 /* thumb unconditional branch */ 509 #define R_ARM_THM_PC11 102 /* thumb unconditional branch */