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 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 */
... ...
... ... @@ -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;
... ...
... ... @@ -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 */
... ...