1 /* Instruction printing code for the ARM
2 Copyright (C) 1994, 95, 96, 97, 98, 99, 2000 Free Software Foundation, Inc.
3 Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
4 Modification by James G. Smith (jsmith@cygnus.co.uk)
6 This file is part of libopcodes.
8 This program is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2 of the License, or (at your option)
13 This program is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
26 #include "coff/internal.h"
30 /* FIXME: This shouldn't be done here */
32 #include "elf/internal.h"
36 #define streq(a,b) (strcmp ((a), (b)) == 0)
40 #define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0)
44 #define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0])
47 static char * arm_conditional[] =
48 {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
49 "hi", "ls", "ge", "lt", "gt", "le", "", "nv"};
54 const char * description;
55 const char * reg_names[16];
59 static arm_regname regnames[] =
61 { "raw" , "Select raw register names",
62 { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}},
63 { "gcc", "Select register names used by GCC",
64 { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc" }},
65 { "std", "Select register names used in ARM's ISA documentation",
66 { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc" }},
67 { "apcs", "Select register names used in the APCS",
68 { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "sl", "fp", "ip", "sp", "lr", "pc" }},
69 { "atpcs", "Select register names used in the ATPCS",
70 { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "IP", "SP", "LR", "PC" }},
71 { "special-atpcs", "Select special register names used in the ATPCS",
72 { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }}
75 /* Default to GCC register name set. */
76 static unsigned int regname_selected = 1;
78 #define NUM_ARM_REGNAMES NUM_ELEM (regnames)
79 #define arm_regnames regnames[regname_selected].reg_names
81 static boolean force_thumb = false;
83 static char * arm_fp_const[] =
84 {"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"};
86 static char * arm_shift[] =
87 {"lsl", "lsr", "asr", "ror"};
89 /* Forward declarations. */
90 static void arm_decode_shift PARAMS ((long, fprintf_ftype, void *));
91 static int print_insn_arm PARAMS ((bfd_vma, struct disassemble_info *, long));
92 static int print_insn_thumb PARAMS ((bfd_vma, struct disassemble_info *, long));
93 static void parse_disassembler_options PARAMS ((char *));
94 static int print_insn PARAMS ((bfd_vma, struct disassemble_info *, boolean));
95 int get_arm_regname_num_options (void);
96 int set_arm_regname_option (int option);
97 int get_arm_regnames (int option, const char **setname,
98 const char **setdescription,
99 const char ***register_names);
103 get_arm_regname_num_options (void)
105 return NUM_ARM_REGNAMES;
109 set_arm_regname_option (int option)
111 int old = regname_selected;
112 regname_selected = option;
117 get_arm_regnames (int option, const char **setname,
118 const char **setdescription,
119 const char ***register_names)
121 *setname = regnames[option].name;
122 *setdescription = regnames[option].description;
123 *register_names = regnames[option].reg_names;
128 arm_decode_shift (given, func, stream)
133 func (stream, "%s", arm_regnames[given & 0xf]);
135 if ((given & 0xff0) != 0)
137 if ((given & 0x10) == 0)
139 int amount = (given & 0xf80) >> 7;
140 int shift = (given & 0x60) >> 5;
146 func (stream, ", rrx");
153 func (stream, ", %s #%d", arm_shift[shift], amount);
156 func (stream, ", %s %s", arm_shift[(given & 0x60) >> 5],
157 arm_regnames[(given & 0xf00) >> 8]);
161 /* Print one instruction from PC on INFO->STREAM.
162 Return the size of the instruction (always 4 on ARM). */
164 print_insn_arm (pc, info, given)
166 struct disassemble_info * info;
169 struct arm_opcode * insn;
170 void * stream = info->stream;
171 fprintf_ftype func = info->fprintf_func;
173 for (insn = arm_opcodes; insn->assembler; insn++)
175 if ((given & insn->mask) == insn->value)
179 for (c = insn->assembler; *c; c++)
190 if (((given & 0x000f0000) == 0x000f0000)
191 && ((given & 0x02000000) == 0))
193 int offset = given & 0xfff;
195 func (stream, "[pc");
197 if (given & 0x01000000)
199 if ((given & 0x00800000) == 0)
203 func (stream, ", #%x]", offset);
207 /* Cope with the possibility of write-back
208 being used. Probably a very dangerous thing
209 for the programmer to do, but who are we to
211 if (given & 0x00200000)
217 func (stream, "], #%x", offset);
219 offset = pc + 8; /* ie ignore the offset. */
222 func (stream, "\t; ");
223 info->print_address_func (offset, info);
228 arm_regnames[(given >> 16) & 0xf]);
229 if ((given & 0x01000000) != 0)
231 if ((given & 0x02000000) == 0)
233 int offset = given & 0xfff;
235 func (stream, ", %s#%d",
236 (((given & 0x00800000) == 0)
237 ? "-" : ""), offset);
241 func (stream, ", %s",
242 (((given & 0x00800000) == 0)
244 arm_decode_shift (given, func, stream);
248 ((given & 0x00200000) != 0) ? "!" : "");
252 if ((given & 0x02000000) == 0)
254 int offset = given & 0xfff;
256 func (stream, "], %s#%d",
257 (((given & 0x00800000) == 0)
258 ? "-" : ""), offset);
264 func (stream, "], %s",
265 (((given & 0x00800000) == 0)
267 arm_decode_shift (given, func, stream);
274 if ((given & 0x004f0000) == 0x004f0000)
276 /* PC relative with immediate offset. */
277 int offset = ((given & 0xf00) >> 4) | (given & 0xf);
279 if ((given & 0x00800000) == 0)
282 func (stream, "[pc, #%x]\t; ", offset);
284 (*info->print_address_func)
285 (offset + pc + 8, info);
290 arm_regnames[(given >> 16) & 0xf]);
291 if ((given & 0x01000000) != 0)
294 if ((given & 0x00400000) == 0x00400000)
297 int offset = ((given & 0xf00) >> 4) | (given & 0xf);
299 func (stream, ", %s#%d",
300 (((given & 0x00800000) == 0)
301 ? "-" : ""), offset);
306 func (stream, ", %s%s",
307 (((given & 0x00800000) == 0)
309 arm_regnames[given & 0xf]);
313 ((given & 0x00200000) != 0) ? "!" : "");
318 if ((given & 0x00400000) == 0x00400000)
321 int offset = ((given & 0xf00) >> 4) | (given & 0xf);
323 func (stream, "], %s#%d",
324 (((given & 0x00800000) == 0)
325 ? "-" : ""), offset);
332 func (stream, "], %s%s",
333 (((given & 0x00800000) == 0)
335 arm_regnames[given & 0xf]);
342 (*info->print_address_func)
343 (BDISP (given) * 4 + pc + 8, info);
348 arm_conditional [(given >> 28) & 0xf]);
357 for (reg = 0; reg < 16; reg++)
358 if ((given & (1 << reg)) != 0)
363 func (stream, "%s", arm_regnames[reg]);
370 if ((given & 0x02000000) != 0)
372 int rotate = (given & 0xf00) >> 7;
373 int immed = (given & 0xff);
374 immed = (((immed << (32 - rotate))
375 | (immed >> rotate)) & 0xffffffff);
376 func (stream, "#%d\t; 0x%x", immed, immed);
379 arm_decode_shift (given, func, stream);
383 if ((given & 0x0000f000) == 0x0000f000)
388 if ((given & 0x01200000) == 0x00200000)
393 if ((given & 0x00000020) == 0x00000020)
400 func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]);
401 if ((given & 0x01000000) != 0)
403 int offset = given & 0xff;
405 func (stream, ", %s#%d]%s",
406 ((given & 0x00800000) == 0 ? "-" : ""),
408 ((given & 0x00200000) != 0 ? "!" : ""));
414 int offset = given & 0xff;
416 func (stream, "], %s#%d",
417 ((given & 0x00800000) == 0 ? "-" : ""),
425 /* Print ARM V5 BLX(1) address: pc+25 bits. */
430 if (given & 0x00800000)
431 /* Is signed, hi bits should be ones. */
432 offset = (-1) ^ 0x00ffffff;
434 /* Offset is (SignExtend(offset field)<<2). */
435 offset += given & 0x00ffffff;
437 address = offset + pc + 8;
439 if (given & 0x01000000)
440 /* H bit allows addressing to 2-byte boundaries. */
443 info->print_address_func (address, info);
460 switch (given & 0x00408000)
477 switch (given & 0x00080080)
489 func (stream, _("<illegal precision>"));
494 switch (given & 0x00408000)
511 switch (given & 0x60)
527 case '0': case '1': case '2': case '3': case '4':
528 case '5': case '6': case '7': case '8': case '9':
530 int bitstart = *c++ - '0';
532 while (*c >= '0' && *c <= '9')
533 bitstart = (bitstart * 10) + *c++ - '0';
540 while (*c >= '0' && *c <= '9')
541 bitend = (bitend * 10) + *c++ - '0';
552 reg = given >> bitstart;
553 reg &= (2 << (bitend - bitstart)) - 1;
555 func (stream, "%s", arm_regnames[reg]);
562 reg = given >> bitstart;
563 reg &= (2 << (bitend - bitstart)) - 1;
565 func (stream, "%d", reg);
572 reg = given >> bitstart;
573 reg &= (2 << (bitend - bitstart)) - 1;
575 func (stream, "0x%08x", reg);
577 /* Some SWI instructions have special
579 if ((given & 0x0fffffff) == 0x0FF00000)
580 func (stream, "\t; IMB");
581 else if ((given & 0x0fffffff) == 0x0FF00001)
582 func (stream, "\t; IMBRange");
589 reg = given >> bitstart;
590 reg &= (2 << (bitend - bitstart)) - 1;
592 func (stream, "%01x", reg & 0xf);
599 reg = given >> bitstart;
600 reg &= (2 << (bitend - bitstart)) - 1;
604 arm_fp_const[reg & 7]);
606 func (stream, "f%d", reg);
616 if ((given & (1 << bitstart)) == 0)
617 func (stream, "%c", *c);
621 if ((given & (1 << bitstart)) != 0)
622 func (stream, "%c", *c);
626 if ((given & (1 << bitstart)) != 0)
627 func (stream, "%c", *c++);
629 func (stream, "%c", *++c);
642 func (stream, "%c", *c);
650 /* Print one instruction from PC on INFO->STREAM.
651 Return the size of the instruction. */
653 print_insn_thumb (pc, info, given)
655 struct disassemble_info * info;
658 struct thumb_opcode * insn;
659 void * stream = info->stream;
660 fprintf_ftype func = info->fprintf_func;
662 for (insn = thumb_opcodes; insn->assembler; insn++)
664 if ((given & insn->mask) == insn->value)
666 char * c = insn->assembler;
668 /* Special processing for Thumb 2 instruction BL sequence: */
669 if (!*c) /* Check for empty (not NULL) assembler string. */
673 info->bytes_per_chunk = 4;
674 info->bytes_per_line = 4;
676 offset = BDISP23 (given);
678 if ((given & 0x10000000) == 0)
680 func (stream, "blx\t");
682 /* The spec says that bit 1 of the branch's destination
683 address comes from bit 1 of the instruction's
684 address and not from the offset in the instruction. */
687 /* func (stream, "*malformed!* "); */
691 offset |= ((pc & 0x2) >> 1);
694 func (stream, "bl\t");
696 info->print_address_func (offset * 2 + pc + 4, info);
701 info->bytes_per_chunk = 2;
702 info->bytes_per_line = 4;
723 reg = (given >> 3) & 0x7;
724 if (given & (1 << 6))
727 func (stream, "%s", arm_regnames[reg]);
736 if (given & (1 << 7))
739 func (stream, "%s", arm_regnames[reg]);
745 arm_conditional [(given >> 8) & 0xf]);
749 if (given & (1 << 8))
753 if (*c == 'O' && (given & (1 << 8)))
763 /* It would be nice if we could spot
764 ranges, and generate the rS-rE format: */
765 for (reg = 0; (reg < 8); reg++)
766 if ((given & (1 << reg)) != 0)
771 func (stream, "%s", arm_regnames[reg]);
779 func (stream, arm_regnames[14] /* "lr" */);
786 func (stream, arm_regnames[15] /* "pc" */);
794 case '0': case '1': case '2': case '3': case '4':
795 case '5': case '6': case '7': case '8': case '9':
797 int bitstart = *c++ - '0';
800 while (*c >= '0' && *c <= '9')
801 bitstart = (bitstart * 10) + *c++ - '0';
810 while (*c >= '0' && *c <= '9')
811 bitend = (bitend * 10) + *c++ - '0';
814 reg = given >> bitstart;
815 reg &= (2 << (bitend - bitstart)) - 1;
819 func (stream, "%s", arm_regnames[reg]);
823 func (stream, "%d", reg);
827 func (stream, "%d", reg << 1);
831 func (stream, "%d", reg << 2);
835 /* PC-relative address -- the bottom two
836 bits of the address are dropped
837 before the calculation. */
838 info->print_address_func
839 (((pc + 4) & ~3) + (reg << 2), info);
843 func (stream, "0x%04x", reg);
847 reg = ((reg ^ (1 << bitend)) - (1 << bitend));
848 func (stream, "%d", reg);
852 reg = ((reg ^ (1 << bitend)) - (1 << bitend));
853 (*info->print_address_func)
854 (reg * 2 + pc + 4, info);
865 if ((given & (1 << bitstart)) != 0)
866 func (stream, "%c", *c);
871 if ((given & (1 << bitstart)) != 0)
872 func (stream, "%c", *c++);
874 func (stream, "%c", *++c);
888 func (stream, "%c", *c);
899 /* Parse an individual disassembler option. */
901 parse_arm_disassembler_option (option)
907 if (strneq (option, "reg-names-", 10))
913 for (i = NUM_ARM_REGNAMES; i--;)
914 if (streq (option, regnames[i].name))
916 regname_selected = i;
921 fprintf (stderr, _("Unrecognised register name set: %s\n"), option);
923 else if (streq (option, "force-thumb"))
925 else if (streq (option, "no-force-thumb"))
928 fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option);
933 /* Parse the string of disassembler options, spliting it at whitespaces. */
935 parse_disassembler_options (options)
945 space = strchr (options, ' ');
950 parse_arm_disassembler_option (options);
955 parse_arm_disassembler_option (options);
960 /* NOTE: There are no checks in these routines that
961 the relevant number of data bytes exist. */
963 print_insn (pc, info, little)
965 struct disassemble_info * info;
973 if (info->disassembler_options)
975 parse_disassembler_options (info->disassembler_options);
977 /* To avoid repeated parsing of these options, we remove them here. */
978 info->disassembler_options = NULL;
981 is_thumb = force_thumb;
983 if (!is_thumb && info->symbols != NULL)
985 if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour)
987 coff_symbol_type * cs;
989 cs = coffsymbol (*info->symbols);
990 is_thumb = ( cs->native->u.syment.n_sclass == C_THUMBEXT
991 || cs->native->u.syment.n_sclass == C_THUMBSTAT
992 || cs->native->u.syment.n_sclass == C_THUMBLABEL
993 || cs->native->u.syment.n_sclass == C_THUMBEXTFUNC
994 || cs->native->u.syment.n_sclass == C_THUMBSTATFUNC);
996 else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour)
998 elf_symbol_type * es;
1001 es = *(elf_symbol_type **)(info->symbols);
1002 type = ELF_ST_TYPE (es->internal_elf_sym.st_info);
1004 is_thumb = (type == STT_ARM_TFUNC) || (type == STT_ARM_16BIT);
1008 info->bytes_per_chunk = 4;
1009 info->display_endian = little ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG;
1013 status = info->read_memory_func (pc, (bfd_byte *) &b[0], 4, info);
1014 if (status != 0 && is_thumb)
1016 info->bytes_per_chunk = 2;
1018 status = info->read_memory_func (pc, (bfd_byte *) b, 2, info);
1024 info->memory_error_func (status, pc, info);
1028 given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
1032 status = info->read_memory_func
1033 (pc & ~ 0x3, (bfd_byte *) &b[0], 4, info);
1036 info->memory_error_func (status, pc, info);
1044 given = (b[2] << 8) | b[3];
1046 status = info->read_memory_func
1047 ((pc + 4) & ~ 0x3, (bfd_byte *) b, 4, info);
1050 info->memory_error_func (status, pc + 4, info);
1054 given |= (b[0] << 24) | (b[1] << 16);
1057 given = (b[0] << 8) | b[1] | (b[2] << 24) | (b[3] << 16);
1060 given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
1063 if (info->flags & INSN_HAS_RELOC)
1064 /* If the instruction has a reloc associated with it, then
1065 the offset field in the instruction will actually be the
1066 addend for the reloc. (We are using REL type relocs).
1067 In such cases, we can ignore the pc when computing
1068 addresses, since the addend is not currently pc-relative. */
1072 status = print_insn_thumb (pc, info, given);
1074 status = print_insn_arm (pc, info, given);
1080 print_insn_big_arm (pc, info)
1082 struct disassemble_info * info;
1084 return print_insn (pc, info, false);
1088 print_insn_little_arm (pc, info)
1090 struct disassemble_info * info;
1092 return print_insn (pc, info, true);
1096 print_arm_disassembler_options (FILE * stream)
1100 fprintf (stream, _("\n\
1101 The following ARM specific disassembler options are supported for use with\n\
1102 the -M switch:\n"));
1104 for (i = NUM_ARM_REGNAMES; i--;)
1105 fprintf (stream, " reg-names-%s %*c%s\n",
1107 14 - strlen (regnames[i].name), ' ',
1108 regnames[i].description);
1110 fprintf (stream, " force-thumb Assume all insns are Thumb insns\n");
1111 fprintf (stream, " no-force-thumb Examine preceeding label to determine an insn's type\n\n");