📄 arm-dis.c
字号:
{ long reg; reg = given >> bitstart; reg &= (2 << (bitend - bitstart)) - 1; func (stream, "%s", arm_regnames[reg]); } break; case 'd': { long reg; reg = given >> bitstart; reg &= (2 << (bitend - bitstart)) - 1; func (stream, "%d", reg); } break; case 'x': { long reg; reg = given >> bitstart; reg &= (2 << (bitend - bitstart)) - 1; func (stream, "0x%08x", reg); /* Some SWI instructions have special meanings. */ if ((given & 0x0fffffff) == 0x0FF00000) func (stream, "\t; IMB"); else if ((given & 0x0fffffff) == 0x0FF00001) func (stream, "\t; IMBRange"); } break; case 'X': { long reg; reg = given >> bitstart; reg &= (2 << (bitend - bitstart)) - 1; func (stream, "%01x", reg & 0xf); } break; case 'f': { long reg; reg = given >> bitstart; reg &= (2 << (bitend - bitstart)) - 1; if (reg > 7) func (stream, "#%s", arm_fp_const[reg & 7]); else func (stream, "f%d", reg); } break; default: abort (); } break; case '`': c++; if ((given & (1 << bitstart)) == 0) func (stream, "%c", *c); break; case '\'': c++; if ((given & (1 << bitstart)) != 0) func (stream, "%c", *c); break; case '?': ++c; if ((given & (1 << bitstart)) != 0) func (stream, "%c", *c++); else func (stream, "%c", *++c); break; default: abort (); } break; default: abort (); } } } else func (stream, "%c", *c); } return 4; } } abort ();}/* Print one instruction from PC on INFO->STREAM. Return the size of the instruction. */static intprint_insn_thumb (pc, info, given) bfd_vma pc; struct disassemble_info * info; long given;{ struct thumb_opcode * insn; void * stream = info->stream; fprintf_ftype func = info->fprintf_func; for (insn = thumb_opcodes; insn->assembler; insn++) { if ((given & insn->mask) == insn->value) { char * c = insn->assembler; /* Special processing for Thumb 2 instruction BL sequence: */ if (!*c) /* Check for empty (not NULL) assembler string. */ { info->bytes_per_chunk = 4; info->bytes_per_line = 4; if ((given & 0x10000000) == 0) func (stream, "blx\t"); else func (stream, "bl\t"); info->print_address_func (BDISP23 (given) * 2 + pc + 4, info); return 4; } else { info->bytes_per_chunk = 2; info->bytes_per_line = 4; given &= 0xffff; for (; *c; c++) { if (*c == '%') { int domaskpc = 0; int domasklr = 0; switch (*++c) { case '%': func (stream, "%%"); break; case 'S': { long reg; reg = (given >> 3) & 0x7; if (given & (1 << 6)) reg += 8; func (stream, "%s", arm_regnames[reg]); } break; case 'D': { long reg; reg = given & 0x7; if (given & (1 << 7)) reg += 8; func (stream, "%s", arm_regnames[reg]); } break; case 'T': func (stream, "%s", arm_conditional [(given >> 8) & 0xf]); break; case 'N': if (given & (1 << 8)) domasklr = 1; /* Fall through. */ case 'O': if (*c == 'O' && (given & (1 << 8))) domaskpc = 1; /* Fall through. */ case 'M': { int started = 0; int reg; func (stream, "{"); /* It would be nice if we could spot ranges, and generate the rS-rE format: */ for (reg = 0; (reg < 8); reg++) if ((given & (1 << reg)) != 0) { if (started) func (stream, ", "); started = 1; func (stream, "%s", arm_regnames[reg]); } if (domasklr) { if (started) func (stream, ", "); started = 1; func (stream, arm_regnames[14] /* "lr" */); } if (domaskpc) { if (started) func (stream, ", "); func (stream, arm_regnames[15] /* "pc" */); } func (stream, "}"); } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { int bitstart = *c++ - '0'; int bitend = 0; while (*c >= '0' && *c <= '9') bitstart = (bitstart * 10) + *c++ - '0'; switch (*c) { case '-': { long reg; c++; while (*c >= '0' && *c <= '9') bitend = (bitend * 10) + *c++ - '0'; if (!bitend) abort (); reg = given >> bitstart; reg &= (2 << (bitend - bitstart)) - 1; switch (*c) { case 'r': func (stream, "%s", arm_regnames[reg]); break; case 'd': func (stream, "%d", reg); break; case 'H': func (stream, "%d", reg << 1); break; case 'W': func (stream, "%d", reg << 2); break; case 'a': /* PC-relative address -- the bottom two bits of the address are dropped before the calculation. */ info->print_address_func (((pc + 4) & ~3) + (reg << 2), info); break; case 'x': func (stream, "0x%04x", reg); break; case 'I': reg = ((reg ^ (1 << bitend)) - (1 << bitend)); func (stream, "%d", reg); break; case 'B': reg = ((reg ^ (1 << bitend)) - (1 << bitend)); (*info->print_address_func) (reg * 2 + pc + 4, info); break; default: abort (); } } break; case '\'': c++; if ((given & (1 << bitstart)) != 0) func (stream, "%c", *c); break; case '?': ++c; if ((given & (1 << bitstart)) != 0) func (stream, "%c", *c++); else func (stream, "%c", *++c); break; default: abort (); } } break; default: abort (); } } else func (stream, "%c", *c); } } return 2; } } /* No match. */ abort ();}/* Parse an individual disassembler option. */voidparse_arm_disassembler_option (option) char * option;{ if (option == NULL) return; if (strneq (option, "reg-names-", 10)) { int i; option += 10; for (i = NUM_ARM_REGNAMES; i--;) if (streq (option, regnames[i].name)) { regname_selected = i; break; } if (i < 0) fprintf (stderr, _("Unrecognised register name set: %s\n"), option); } else if (streq (option, "force-thumb")) force_thumb = 1; else if (streq (option, "no-force-thumb")) force_thumb = 0; else fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option); return;}/* Parse the string of disassembler options, spliting it at whitespaces. */static voidparse_disassembler_options (options) char * options;{ char * space; if (options == NULL) return; do { space = strchr (options, ' '); if (space) { * space = '\0'; parse_arm_disassembler_option (options); * space = ' '; options = space + 1; } else parse_arm_disassembler_option (options); } while (space);}/* NOTE: There are no checks in these routines that the relevant number of data bytes exist. */static intprint_insn (pc, info, little) bfd_vma pc; struct disassemble_info * info; boolean little;{ unsigned char b[4]; long given; int status; int is_thumb; if (info->disassembler_options) { parse_disassembler_options (info->disassembler_options); /* To avoid repeated parsing of these options, we remove them here. */ info->disassembler_options = NULL; } is_thumb = force_thumb; if (!is_thumb && info->symbols != NULL) { if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour) { coff_symbol_type * cs; cs = coffsymbol (*info->symbols); is_thumb = ( cs->native->u.syment.n_sclass == C_THUMBEXT || cs->native->u.syment.n_sclass == C_THUMBSTAT || cs->native->u.syment.n_sclass == C_THUMBLABEL || cs->native->u.syment.n_sclass == C_THUMBEXTFUNC || cs->native->u.syment.n_sclass == C_THUMBSTATFUNC); } else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour) { elf_symbol_type * es; unsigned int type; es = *(elf_symbol_type **)(info->symbols); type = ELF_ST_TYPE (es->internal_elf_sym.st_info); is_thumb = (type == STT_ARM_TFUNC) || (type == STT_ARM_16BIT); } } info->bytes_per_chunk = 4; info->display_endian = little ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG; if (little) { status = info->read_memory_func (pc, (bfd_byte *) &b[0], 4, info); if (status != 0 && is_thumb) { info->bytes_per_chunk = 2; status = info->read_memory_func (pc, (bfd_byte *) b, 2, info); b[3] = b[2] = 0; } if (status != 0) { info->memory_error_func (status, pc, info); return -1; } given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24); } else { status = info->read_memory_func (pc & ~ 0x3, (bfd_byte *) &b[0], 4, info); if (status != 0) { info->memory_error_func (status, pc, info); return -1; } if (is_thumb) { if (pc & 0x2) { given = (b[2] << 8) | b[3]; status = info->read_memory_func ((pc + 4) & ~ 0x3, (bfd_byte *) b, 4, info); if (status != 0) { info->memory_error_func (status, pc + 4, info); return -1; } given |= (b[0] << 24) | (b[1] << 16); } else given = (b[0] << 8) | b[1] | (b[2] << 24) | (b[3] << 16); } else given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]); } if (info->flags & INSN_HAS_RELOC) /* If the instruction has a reloc associated with it, then the offset field in the instruction will actually be the addend for the reloc. (We are using REL type relocs). In such cases, we can ignore the pc when computing addresses, since the addend is not currently pc-relative. */ pc = 0; if (is_thumb) status = print_insn_thumb (pc, info, given); else status = print_insn_arm (pc, info, given); return status;}intprint_insn_big_arm (pc, info) bfd_vma pc; struct disassemble_info * info;{ return print_insn (pc, info, false);}intprint_insn_little_arm (pc, info) bfd_vma pc; struct disassemble_info * info;{ return print_insn (pc, info, true);}voidprint_arm_disassembler_options (FILE * stream){ int i; fprintf (stream, _("\n\The following ARM specific disassembler options are supported for use with\n\the -M switch:\n")); for (i = NUM_ARM_REGNAMES; i--;) fprintf (stream, " reg-names-%s %*c%s\n", regnames[i].name, 14 - strlen (regnames[i].name), ' ', regnames[i].description); fprintf (stream, " force-thumb Assume all insns are Thumb insns\n"); fprintf (stream, " no-force-thumb Examine preceeding label to determine an insn's type\n\n");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -