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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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");
|