79 |
#define elf_check_arch(x) ((x) == EM_SPARCV9) |
#define elf_check_arch(x) ((x) == EM_SPARCV9) |
80 |
#define ELF_USES_RELOCA |
#define ELF_USES_RELOCA |
81 |
|
|
82 |
|
#elif defined(HOST_ARM) |
83 |
|
|
84 |
|
#define ELF_CLASS ELFCLASS32 |
85 |
|
#define ELF_ARCH EM_ARM |
86 |
|
#define elf_check_arch(x) ((x) == EM_ARM) |
87 |
|
#define ELF_USES_RELOC |
88 |
|
|
89 |
#else |
#else |
90 |
#error unsupported CPU - please update the code |
#error unsupported CPU - please update the code |
91 |
#endif |
#endif |
308 |
return 1; |
return 1; |
309 |
} |
} |
310 |
|
|
311 |
|
#ifdef HOST_ARM |
312 |
|
|
313 |
|
int arm_emit_ldr_info(const char *name, unsigned long start_offset, |
314 |
|
FILE *outfile, uint8_t *p_start, uint8_t *p_end, |
315 |
|
ELF_RELOC *relocs, int nb_relocs) |
316 |
|
{ |
317 |
|
uint8_t *p; |
318 |
|
uint32_t insn; |
319 |
|
int offset, min_offset, pc_offset, data_size; |
320 |
|
uint8_t data_allocated[1024]; |
321 |
|
unsigned int data_index; |
322 |
|
|
323 |
|
memset(data_allocated, 0, sizeof(data_allocated)); |
324 |
|
|
325 |
|
p = p_start; |
326 |
|
min_offset = p_end - p_start; |
327 |
|
while (p < p_start + min_offset) { |
328 |
|
insn = get32((uint32_t *)p); |
329 |
|
if ((insn & 0x0d5f0000) == 0x051f0000) { |
330 |
|
/* ldr reg, [pc, #im] */ |
331 |
|
offset = insn & 0xfff; |
332 |
|
if (!(insn & 0x00800000)) |
333 |
|
offset = -offset; |
334 |
|
if ((offset & 3) !=0) |
335 |
|
error("%s:%04x: ldr pc offset must be 32 bit aligned", |
336 |
|
name, start_offset + p - p_start); |
337 |
|
pc_offset = p - p_start + offset + 8; |
338 |
|
if (pc_offset <= (p - p_start) || |
339 |
|
pc_offset >= (p_end - p_start)) |
340 |
|
error("%s:%04x: ldr pc offset must point inside the function code", |
341 |
|
name, start_offset + p - p_start); |
342 |
|
if (pc_offset < min_offset) |
343 |
|
min_offset = pc_offset; |
344 |
|
if (outfile) { |
345 |
|
/* ldr position */ |
346 |
|
fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n", |
347 |
|
p - p_start); |
348 |
|
/* ldr data index */ |
349 |
|
data_index = ((p_end - p_start) - pc_offset - 4) >> 2; |
350 |
|
fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr + %d;\n", |
351 |
|
data_index); |
352 |
|
fprintf(outfile, " arm_ldr_ptr++;\n"); |
353 |
|
if (data_index >= sizeof(data_allocated)) |
354 |
|
error("%s: too many data", name); |
355 |
|
if (!data_allocated[data_index]) { |
356 |
|
ELF_RELOC *rel; |
357 |
|
int i, addend, type; |
358 |
|
const char *sym_name, *p; |
359 |
|
char relname[1024]; |
360 |
|
|
361 |
|
data_allocated[data_index] = 1; |
362 |
|
|
363 |
|
/* data value */ |
364 |
|
addend = get32((uint32_t *)(p_start + pc_offset)); |
365 |
|
relname[0] = '\0'; |
366 |
|
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { |
367 |
|
if (rel->r_offset == (pc_offset + start_offset)) { |
368 |
|
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; |
369 |
|
/* the compiler leave some unnecessary references to the code */ |
370 |
|
if (strstart(sym_name, "__op_param", &p)) { |
371 |
|
snprintf(relname, sizeof(relname), "param%s", p); |
372 |
|
} else { |
373 |
|
snprintf(relname, sizeof(relname), "(long)(&%s)", sym_name); |
374 |
|
} |
375 |
|
type = ELF32_R_TYPE(rel->r_info); |
376 |
|
if (type != R_ARM_ABS32) |
377 |
|
error("%s: unsupported data relocation", name); |
378 |
|
break; |
379 |
|
} |
380 |
|
} |
381 |
|
fprintf(outfile, " arm_data_ptr[%d] = 0x%x", |
382 |
|
data_index, addend); |
383 |
|
if (relname[0] != '\0') |
384 |
|
fprintf(outfile, " + %s", relname); |
385 |
|
fprintf(outfile, ";\n"); |
386 |
|
} |
387 |
|
} |
388 |
|
} |
389 |
|
p += 4; |
390 |
|
} |
391 |
|
data_size = (p_end - p_start) - min_offset; |
392 |
|
if (data_size > 0 && outfile) { |
393 |
|
fprintf(outfile, " arm_data_ptr += %d;\n", data_size >> 2); |
394 |
|
} |
395 |
|
|
396 |
|
/* the last instruction must be a mov pc, lr */ |
397 |
|
if (p == p_start) |
398 |
|
goto arm_ret_error; |
399 |
|
p -= 4; |
400 |
|
insn = get32((uint32_t *)p); |
401 |
|
if ((insn & 0xffff0000) != 0xe91b0000) { |
402 |
|
arm_ret_error: |
403 |
|
if (!outfile) |
404 |
|
printf("%s: invalid epilog\n", name); |
405 |
|
} |
406 |
|
return p - p_start; |
407 |
|
} |
408 |
|
#endif |
409 |
|
|
410 |
|
|
411 |
#define MAX_ARGS 3 |
#define MAX_ARGS 3 |
412 |
|
|
413 |
/* generate op code */ |
/* generate op code */ |
495 |
case EM_SPARC: |
case EM_SPARC: |
496 |
case EM_SPARC32PLUS: |
case EM_SPARC32PLUS: |
497 |
{ |
{ |
498 |
uint32_t start_insn, end_insn1, end_insn2, skip_insn; |
uint32_t start_insn, end_insn1, end_insn2; |
499 |
uint8_t *p; |
uint8_t *p; |
500 |
p = (void *)(p_end - 8); |
p = (void *)(p_end - 8); |
501 |
if (p <= p_start) |
if (p <= p_start) |
513 |
} else { |
} else { |
514 |
error("No save at the beginning of %s", name); |
error("No save at the beginning of %s", name); |
515 |
} |
} |
516 |
|
#if 0 |
517 |
/* Skip a preceeding nop, if present. */ |
/* Skip a preceeding nop, if present. */ |
518 |
if (p > p_start) { |
if (p > p_start) { |
519 |
skip_insn = get32((uint32_t *)(p - 0x4)); |
skip_insn = get32((uint32_t *)(p - 0x4)); |
520 |
if (skip_insn == 0x01000000) |
if (skip_insn == 0x01000000) |
521 |
p -= 4; |
p -= 4; |
522 |
} |
} |
523 |
|
#endif |
524 |
copy_size = p - p_start; |
copy_size = p - p_start; |
525 |
} |
} |
526 |
break; |
break; |
555 |
copy_size = p - p_start; |
copy_size = p - p_start; |
556 |
} |
} |
557 |
break; |
break; |
558 |
|
#ifdef HOST_ARM |
559 |
|
case EM_ARM: |
560 |
|
if ((p_end - p_start) <= 16) |
561 |
|
error("%s: function too small", name); |
562 |
|
if (get32((uint32_t *)p_start) != 0xe1a0c00d || |
563 |
|
(get32((uint32_t *)(p_start + 4)) & 0xffff0000) != 0xe92d0000 || |
564 |
|
get32((uint32_t *)(p_start + 8)) != 0xe24cb004) |
565 |
|
error("%s: invalid prolog", name); |
566 |
|
p_start += 12; |
567 |
|
start_offset += 12; |
568 |
|
copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end, |
569 |
|
relocs, nb_relocs); |
570 |
|
break; |
571 |
|
#endif |
572 |
default: |
default: |
573 |
error("unknown ELF architecture"); |
error("unknown ELF architecture"); |
574 |
} |
} |
579 |
|
|
580 |
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { |
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { |
581 |
if (rel->r_offset >= start_offset && |
if (rel->r_offset >= start_offset && |
582 |
rel->r_offset < start_offset + copy_size) { |
rel->r_offset < start_offset + (p_end - p_start)) { |
583 |
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; |
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; |
584 |
if (strstart(sym_name, "__op_param", &p)) { |
if (strstart(sym_name, "__op_param", &p)) { |
585 |
n = strtoul(p, NULL, 10); |
n = strtoul(p, NULL, 10); |
617 |
|
|
618 |
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { |
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { |
619 |
if (rel->r_offset >= start_offset && |
if (rel->r_offset >= start_offset && |
620 |
rel->r_offset < start_offset + copy_size) { |
rel->r_offset < start_offset + (p_end - p_start)) { |
621 |
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; |
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; |
622 |
if (*sym_name && |
if (*sym_name && |
623 |
!strstart(sym_name, "__op_param", NULL) && |
!strstart(sym_name, "__op_param", NULL) && |
1021 |
} |
} |
1022 |
} |
} |
1023 |
} |
} |
1024 |
|
#elif defined(HOST_ARM) |
1025 |
|
{ |
1026 |
|
char name[256]; |
1027 |
|
int type; |
1028 |
|
int addend; |
1029 |
|
|
1030 |
|
arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end, |
1031 |
|
relocs, nb_relocs); |
1032 |
|
|
1033 |
|
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { |
1034 |
|
if (rel->r_offset >= start_offset && |
1035 |
|
rel->r_offset < start_offset + copy_size) { |
1036 |
|
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name; |
1037 |
|
/* the compiler leave some unnecessary references to the code */ |
1038 |
|
if (sym_name[0] == '\0') |
1039 |
|
continue; |
1040 |
|
if (strstart(sym_name, "__op_param", &p)) { |
1041 |
|
snprintf(name, sizeof(name), "param%s", p); |
1042 |
|
} else { |
1043 |
|
snprintf(name, sizeof(name), "(long)(&%s)", sym_name); |
1044 |
|
} |
1045 |
|
type = ELF32_R_TYPE(rel->r_info); |
1046 |
|
addend = get32((uint32_t *)(text + rel->r_offset)); |
1047 |
|
switch(type) { |
1048 |
|
case R_ARM_ABS32: |
1049 |
|
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", |
1050 |
|
rel->r_offset - start_offset, name, addend); |
1051 |
|
break; |
1052 |
|
case R_ARM_PC24: |
1053 |
|
fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n", |
1054 |
|
rel->r_offset - start_offset, addend, name); |
1055 |
|
break; |
1056 |
|
default: |
1057 |
|
error("unsupported arm relocation (%d)", type); |
1058 |
|
} |
1059 |
|
} |
1060 |
|
} |
1061 |
|
} |
1062 |
#else |
#else |
1063 |
#error unsupported CPU |
#error unsupported CPU |
1064 |
#endif |
#endif |
1234 |
"{\n" |
"{\n" |
1235 |
" uint8_t *gen_code_ptr;\n" |
" uint8_t *gen_code_ptr;\n" |
1236 |
" const uint16_t *opc_ptr;\n" |
" const uint16_t *opc_ptr;\n" |
1237 |
" const uint32_t *opparam_ptr;\n" |
" const uint32_t *opparam_ptr;\n"); |
1238 |
|
|
1239 |
|
#ifdef HOST_ARM |
1240 |
|
fprintf(outfile, |
1241 |
|
" uint8_t *last_gen_code_ptr = gen_code_buf;\n" |
1242 |
|
" LDREntry *arm_ldr_ptr = arm_ldr_table;\n" |
1243 |
|
" uint32_t *arm_data_ptr = arm_data_table;\n"); |
1244 |
|
#endif |
1245 |
|
|
1246 |
|
fprintf(outfile, |
1247 |
|
"\n" |
1248 |
" gen_code_ptr = gen_code_buf;\n" |
" gen_code_ptr = gen_code_buf;\n" |
1249 |
" opc_ptr = opc_buf;\n" |
" opc_ptr = opc_buf;\n" |
1250 |
" opparam_ptr = opparam_buf;\n"); |
" opparam_ptr = opparam_buf;\n"); |
1251 |
|
|
1252 |
/* Generate prologue, if needed. */ |
/* Generate prologue, if needed. */ |
|
switch(ELF_ARCH) { |
|
|
case EM_SPARC: |
|
|
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c23a080; /* sub %%sp, 128, %%sp */\n"); |
|
|
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc27a080; /* sub %%fp, 128, %%fp */\n"); |
|
|
break; |
|
|
|
|
|
case EM_SPARCV9: |
|
|
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c23a100; /* sub %%sp, 256, %%sp */\n"); |
|
|
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc27a100; /* sub %%fp, 256, %%fp */\n"); |
|
|
break; |
|
|
}; |
|
1253 |
|
|
1254 |
fprintf(outfile, |
fprintf(outfile, |
1255 |
" for(;;) {\n" |
" for(;;) {\n" |
1274 |
fprintf(outfile, |
fprintf(outfile, |
1275 |
" default:\n" |
" default:\n" |
1276 |
" goto the_end;\n" |
" goto the_end;\n" |
1277 |
" }\n" |
" }\n"); |
1278 |
|
|
1279 |
|
#ifdef HOST_ARM |
1280 |
|
/* generate constant table if needed */ |
1281 |
|
fprintf(outfile, |
1282 |
|
" if ((gen_code_ptr - last_gen_code_ptr) >= (MAX_FRAG_SIZE - MAX_OP_SIZE)) {\n" |
1283 |
|
" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 1);\n" |
1284 |
|
" last_gen_code_ptr = gen_code_ptr;\n" |
1285 |
|
" arm_ldr_ptr = arm_ldr_table;\n" |
1286 |
|
" arm_data_ptr = arm_data_table;\n" |
1287 |
|
" }\n"); |
1288 |
|
#endif |
1289 |
|
|
1290 |
|
|
1291 |
|
fprintf(outfile, |
1292 |
" }\n" |
" }\n" |
1293 |
" the_end:\n" |
" the_end:\n" |
1294 |
); |
); |
1312 |
break; |
break; |
1313 |
case EM_SPARC: |
case EM_SPARC: |
1314 |
case EM_SPARC32PLUS: |
case EM_SPARC32PLUS: |
|
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0xbc07a080; /* add %%fp, 256, %%fp */\n"); |
|
1315 |
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c62008; /* jmpl %%i0 + 8, %%g0 */\n"); |
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c62008; /* jmpl %%i0 + 8, %%g0 */\n"); |
1316 |
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x9c03a080; /* add %%sp, 256, %%sp */\n"); |
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x01000000; /* nop */\n"); |
1317 |
break; |
break; |
1318 |
case EM_SPARCV9: |
case EM_SPARCV9: |
1319 |
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c7e008; /* ret */\n"); |
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81c7e008; /* ret */\n"); |
1320 |
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81e80000; /* restore */\n"); |
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x81e80000; /* restore */\n"); |
1321 |
break; |
break; |
1322 |
|
case EM_ARM: |
1323 |
|
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"); |
1324 |
|
break; |
1325 |
default: |
default: |
1326 |
error("unknown ELF architecture"); |
error("unknown ELF architecture"); |
1327 |
} |
} |