📄 dyngen.c
字号:
int offset, min_offset, pc_offset, data_size; uint8_t data_allocated[1024]; unsigned int data_index; memset(data_allocated, 0, sizeof(data_allocated)); p = p_start; min_offset = p_end - p_start; while (p < p_start + min_offset) { insn = get32((uint32_t *)p); if ((insn & 0x0d5f0000) == 0x051f0000) { /* ldr reg, [pc, #im] */ offset = insn & 0xfff; if (!(insn & 0x00800000)) offset = -offset; if ((offset & 3) !=0) error("%s:%04x: ldr pc offset must be 32 bit aligned", name, start_offset + p - p_start); pc_offset = p - p_start + offset + 8; if (pc_offset <= (p - p_start) || pc_offset >= (p_end - p_start)) error("%s:%04x: ldr pc offset must point inside the function code", name, start_offset + p - p_start); if (pc_offset < min_offset) min_offset = pc_offset; if (outfile) { /* ldr position */ fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n", p - p_start); /* ldr data index */ data_index = ((p_end - p_start) - pc_offset - 4) >> 2; fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr + %d;\n", data_index); fprintf(outfile, " arm_ldr_ptr++;\n"); if (data_index >= sizeof(data_allocated)) error("%s: too many data", name); if (!data_allocated[data_index]) { ELF_RELOC *rel; int i, addend, type; const char *sym_name, *p; char relname[1024]; data_allocated[data_index] = 1; /* data value */ addend = get32((uint32_t *)(p_start + pc_offset)); relname[0] = '\0'; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { if (rel->r_offset == (pc_offset + start_offset)) { sym_name = get_rel_sym_name(rel); /* the compiler leave some unnecessary references to the code */ get_reloc_expr(relname, sizeof(relname), sym_name); type = ELF32_R_TYPE(rel->r_info); if (type != R_ARM_ABS32) error("%s: unsupported data relocation", name); break; } } fprintf(outfile, " arm_data_ptr[%d] = 0x%x", data_index, addend); if (relname[0] != '\0') fprintf(outfile, " + %s", relname); fprintf(outfile, ";\n"); } } } p += 4; } data_size = (p_end - p_start) - min_offset; if (data_size > 0 && outfile) { fprintf(outfile, " arm_data_ptr += %d;\n", data_size >> 2); } /* the last instruction must be a mov pc, lr */ if (p == p_start) goto arm_ret_error; p -= 4; insn = get32((uint32_t *)p); if ((insn & 0xffff0000) != 0xe91b0000) { arm_ret_error: if (!outfile) printf("%s: invalid epilog\n", name); } return p - p_start; }#endif#define MAX_ARGS 3/* generate op code */void gen_code(const char *name, host_ulong offset, host_ulong size, FILE *outfile, int gen_switch){ int copy_size = 0; uint8_t *p_start, *p_end; host_ulong start_offset; int nb_args, i, n; uint8_t args_present[MAX_ARGS]; const char *sym_name, *p; EXE_RELOC *rel; /* Compute exact size excluding prologue and epilogue instructions. * Increment start_offset to skip epilogue instructions, then compute * copy_size the indicate the size of the remaining instructions (in * bytes). */ p_start = text + offset; p_end = p_start + size; start_offset = offset;#if defined(HOST_I386) || defined(HOST_X86_64)#ifdef CONFIG_FORMAT_COFF { uint8_t *p; p = p_end - 1; if (p == p_start) error("empty code for %s", name); while (*p != 0xc3) { p--; if (p <= p_start) error("ret or jmp expected at the end of %s", name); } copy_size = p - p_start; }#else { int len; len = p_end - p_start; if (len == 0) error("empty code for %s", name); if (p_end[-1] == 0xc3) { len--; } else { error("ret or jmp expected at the end of %s", name); } copy_size = len; }#endif #elif defined(HOST_PPC) { uint8_t *p; p = (void *)(p_end - 4); if (p == p_start) error("empty code for %s", name); if (get32((uint32_t *)p) != 0x4e800020) error("blr expected at the end of %s", name); copy_size = p - p_start; }#elif defined(HOST_S390) { uint8_t *p; p = (void *)(p_end - 2); if (p == p_start) error("empty code for %s", name); if (get16((uint16_t *)p) != 0x07fe && get16((uint16_t *)p) != 0x07f4) error("br %%r14 expected at the end of %s", name); copy_size = p - p_start; }#elif defined(HOST_ALPHA) { uint8_t *p; p = p_end - 4;#if 0 /* XXX: check why it occurs */ if (p == p_start) error("empty code for %s", name);#endif if (get32((uint32_t *)p) != 0x6bfa8001) error("ret expected at the end of %s", name); copy_size = p - p_start; }#elif defined(HOST_IA64) { uint8_t *p; p = (void *)(p_end - 4); if (p == p_start) error("empty code for %s", name); /* br.ret.sptk.many b0;; */ /* 08 00 84 00 */ if (get32((uint32_t *)p) != 0x00840008) error("br.ret.sptk.many b0;; expected at the end of %s", name); copy_size = p_end - p_start; }#elif defined(HOST_SPARC) { uint32_t start_insn, end_insn1, end_insn2; uint8_t *p; p = (void *)(p_end - 8); if (p <= p_start) error("empty code for %s", name); start_insn = get32((uint32_t *)(p_start + 0x0)); end_insn1 = get32((uint32_t *)(p + 0x0)); end_insn2 = get32((uint32_t *)(p + 0x4)); if ((start_insn & ~0x1fff) == 0x9de3a000) { p_start += 0x4; start_offset += 0x4; if ((int)(start_insn | ~0x1fff) < -128) error("Found bogus save at the start of %s", name); if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000) error("ret; restore; not found at end of %s", name); } else { error("No save at the beginning of %s", name); }#if 0 /* Skip a preceeding nop, if present. */ if (p > p_start) { skip_insn = get32((uint32_t *)(p - 0x4)); if (skip_insn == 0x01000000) p -= 4; }#endif copy_size = p - p_start; }#elif defined(HOST_SPARC64) { uint32_t start_insn, end_insn1, end_insn2, skip_insn; uint8_t *p; p = (void *)(p_end - 8); if (p <= p_start) error("empty code for %s", name); start_insn = get32((uint32_t *)(p_start + 0x0)); end_insn1 = get32((uint32_t *)(p + 0x0)); end_insn2 = get32((uint32_t *)(p + 0x4)); if ((start_insn & ~0x1fff) == 0x9de3a000) { p_start += 0x4; start_offset += 0x4; if ((int)(start_insn | ~0x1fff) < -256) error("Found bogus save at the start of %s", name); if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000) error("ret; restore; not found at end of %s", name); } else { error("No save at the beginning of %s", name); } /* Skip a preceeding nop, if present. */ if (p > p_start) { skip_insn = get32((uint32_t *)(p - 0x4)); if (skip_insn == 0x01000000) p -= 4; } copy_size = p - p_start; }#elif defined(HOST_ARM) { if ((p_end - p_start) <= 16) error("%s: function too small", name); if (get32((uint32_t *)p_start) != 0xe1a0c00d || (get32((uint32_t *)(p_start + 4)) & 0xffff0000) != 0xe92d0000 || get32((uint32_t *)(p_start + 8)) != 0xe24cb004) error("%s: invalid prolog", name); p_start += 12; start_offset += 12; copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end, relocs, nb_relocs); }#elif defined(HOST_M68K) { uint8_t *p; p = (void *)(p_end - 2); if (p == p_start) error("empty code for %s", name); // remove NOP's, probably added for alignment while ((get16((uint16_t *)p) == 0x4e71) && (p>p_start)) p -= 2; if (get16((uint16_t *)p) != 0x4e75) error("rts expected at the end of %s", name); copy_size = p - p_start; }#else#error unsupported CPU#endif /* compute the number of arguments by looking at the relocations */ for(i = 0;i < MAX_ARGS; i++) args_present[i] = 0; for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { host_ulong offset = get_rel_offset(rel); if (offset >= start_offset && offset < start_offset + (p_end - p_start)) { sym_name = get_rel_sym_name(rel); if(!sym_name) continue; if (strstart(sym_name, "__op_param", &p) || strstart(sym_name, "__op_gen_label", &p)) { n = strtoul(p, NULL, 10); if (n > MAX_ARGS) error("too many arguments in %s", name); args_present[n - 1] = 1; } } } nb_args = 0; while (nb_args < MAX_ARGS && args_present[nb_args]) nb_args++; for(i = nb_args; i < MAX_ARGS; i++) { if (args_present[i]) error("inconsistent argument numbering in %s", name); } if (gen_switch == 2) { fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size); } else if (gen_switch == 1) { /* output C code */ fprintf(outfile, "case INDEX_%s: {\n", name); if (nb_args > 0) { fprintf(outfile, " long "); for(i = 0; i < nb_args; i++) { if (i != 0) fprintf(outfile, ", "); fprintf(outfile, "param%d", i + 1); } fprintf(outfile, ";\n"); }#if defined(HOST_IA64) fprintf(outfile, " extern char %s;\n", name);#else fprintf(outfile, " extern void %s();\n", name);#endif for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) { host_ulong offset = get_rel_offset(rel); if (offset >= start_offset && offset < start_offset + (p_end - p_start)) { sym_name = get_rel_sym_name(rel); if(!sym_name) continue; if (*sym_name && !strstart(sym_name, "__op_param", NULL) && !strstart(sym_name, "__op_jmp", NULL) && !strstart(sym_name, "__op_gen_label", NULL)) {#if defined(HOST_SPARC) if (sym_name[0] == '.') { fprintf(outfile, "extern char __dot_%s __asm__(\"%s\");\n", sym_name+1, sym_name); continue; }#endif#if defined(__APPLE__)/* set __attribute((unused)) on darwin because we wan't to avoid warning when we don't use the symbol */ fprintf(outfile, "extern char %s __attribute__((unused));\n", sym_name);#elif defined(HOST_IA64) if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B) /* * PCREL21 br.call targets generally * are out of range and need to go * through an "import stub". */ fprintf(outfile, " extern char %s;\n", sym_name);#else fprintf(outfile, "extern char %s;\n", sym_name);#endif } } } fprintf(outfile, " memcpy(gen_code_ptr, (void *)((char *)&%s+%d), %d);\n", name, (int)(start_offset - offset), copy_size); /* emit code offset information */ { EXE_SYM *sym; const char *sym_name, *p; unsigned long val; int n; for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { sym_name = get_sym_name(sym); if (strstart(sym_name, "__op_label", &p)) { uint8_t *ptr; unsigned long offset; /* test if the variable refers to a label inside the code we are generating */#ifdef CONFIG_FORMAT_COFF if (sym->st_shndx == text_shndx) { ptr = sdata[coff_text_shndx]; } else if (sym->st_shndx == data_shndx) { ptr = sdata[coff_data_shndx]; } else { ptr = NULL; }#elif defined(CONFIG_FORMAT_MACH) if(!sym->n_sect) continue; ptr = sdata[sym->n_sect-1];#else ptr = sdata[sym->st_shndx];#endif if (!ptr) error("__op_labelN in invalid section"); offset = sym->st_value;#ifdef CONFIG_FORMAT_MACH offset -= section_hdr[sym->n_sect-1].addr;#endif val = *(unsigned long *)(ptr + offset);#ifdef ELF_USES_RELOCA { int reloc_shndx, nb_relocs1, j; /* try to find a matching relocation */ reloc_shndx = find_reloc(sym->st_shndx); if (reloc_shndx) { nb_relocs1 = shdr[reloc_shndx].sh_size / shdr[reloc_shndx].sh_entsize; rel = (ELF_RELOC *)sdata[reloc_shndx]; for(j = 0; j < nb_relocs1; j++) { if (rel->r_offset == offset) { val = rel->r_addend; break; } rel++; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -