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. */
671 info
->bytes_per_chunk
= 4;
672 info
->bytes_per_line
= 4;
674 if ((given
& 0x10000000) == 0)
675 func (stream
, "blx\t");
677 func (stream
, "bl\t");
679 info
->print_address_func (BDISP23 (given
) * 2 + pc
+ 4, info
);
684 info
->bytes_per_chunk
= 2;
685 info
->bytes_per_line
= 4;
706 reg
= (given
>> 3) & 0x7;
707 if (given
& (1 << 6))
710 func (stream
, "%s", arm_regnames
[reg
]);
719 if (given
& (1 << 7))
722 func (stream
, "%s", arm_regnames
[reg
]);
728 arm_conditional
[(given
>> 8) & 0xf]);
732 if (given
& (1 << 8))
736 if (*c
== 'O' && (given
& (1 << 8)))
746 /* It would be nice if we could spot
747 ranges, and generate the rS-rE format: */
748 for (reg
= 0; (reg
< 8); reg
++)
749 if ((given
& (1 << reg
)) != 0)
754 func (stream
, "%s", arm_regnames
[reg
]);
762 func (stream
, arm_regnames
[14] /* "lr" */);
769 func (stream
, arm_regnames
[15] /* "pc" */);
777 case '0': case '1': case '2': case '3': case '4':
778 case '5': case '6': case '7': case '8': case '9':
780 int bitstart
= *c
++ - '0';
783 while (*c
>= '0' && *c
<= '9')
784 bitstart
= (bitstart
* 10) + *c
++ - '0';
793 while (*c
>= '0' && *c
<= '9')
794 bitend
= (bitend
* 10) + *c
++ - '0';
797 reg
= given
>> bitstart
;
798 reg
&= (2 << (bitend
- bitstart
)) - 1;
802 func (stream
, "%s", arm_regnames
[reg
]);
806 func (stream
, "%d", reg
);
810 func (stream
, "%d", reg
<< 1);
814 func (stream
, "%d", reg
<< 2);
818 /* PC-relative address -- the bottom two
819 bits of the address are dropped
820 before the calculation. */
821 info
->print_address_func
822 (((pc
+ 4) & ~3) + (reg
<< 2), info
);
826 func (stream
, "0x%04x", reg
);
830 reg
= ((reg
^ (1 << bitend
)) - (1 << bitend
));
831 func (stream
, "%d", reg
);
835 reg
= ((reg
^ (1 << bitend
)) - (1 << bitend
));
836 (*info
->print_address_func
)
837 (reg
* 2 + pc
+ 4, info
);
848 if ((given
& (1 << bitstart
)) != 0)
849 func (stream
, "%c", *c
);
854 if ((given
& (1 << bitstart
)) != 0)
855 func (stream
, "%c", *c
++);
857 func (stream
, "%c", *++c
);
871 func (stream
, "%c", *c
);
882 /* Parse an individual disassembler option. */
884 parse_arm_disassembler_option (option
)
890 if (strneq (option
, "reg-names-", 10))
896 for (i
= NUM_ARM_REGNAMES
; i
--;)
897 if (streq (option
, regnames
[i
].name
))
899 regname_selected
= i
;
904 fprintf (stderr
, _("Unrecognised register name set: %s\n"), option
);
906 else if (streq (option
, "force-thumb"))
908 else if (streq (option
, "no-force-thumb"))
911 fprintf (stderr
, _("Unrecognised disassembler option: %s\n"), option
);
916 /* Parse the string of disassembler options, spliting it at whitespaces. */
918 parse_disassembler_options (options
)
928 space
= strchr (options
, ' ');
933 parse_arm_disassembler_option (options
);
938 parse_arm_disassembler_option (options
);
943 /* NOTE: There are no checks in these routines that
944 the relevant number of data bytes exist. */
946 print_insn (pc
, info
, little
)
948 struct disassemble_info
* info
;
956 if (info
->disassembler_options
)
958 parse_disassembler_options (info
->disassembler_options
);
960 /* To avoid repeated parsing of these options, we remove them here. */
961 info
->disassembler_options
= NULL
;
964 is_thumb
= force_thumb
;
966 if (!is_thumb
&& info
->symbols
!= NULL
)
968 if (bfd_asymbol_flavour (*info
->symbols
) == bfd_target_coff_flavour
)
970 coff_symbol_type
* cs
;
972 cs
= coffsymbol (*info
->symbols
);
973 is_thumb
= ( cs
->native
->u
.syment
.n_sclass
== C_THUMBEXT
974 || cs
->native
->u
.syment
.n_sclass
== C_THUMBSTAT
975 || cs
->native
->u
.syment
.n_sclass
== C_THUMBLABEL
976 || cs
->native
->u
.syment
.n_sclass
== C_THUMBEXTFUNC
977 || cs
->native
->u
.syment
.n_sclass
== C_THUMBSTATFUNC
);
979 else if (bfd_asymbol_flavour (*info
->symbols
) == bfd_target_elf_flavour
)
981 elf_symbol_type
* es
;
984 es
= *(elf_symbol_type
**)(info
->symbols
);
985 type
= ELF_ST_TYPE (es
->internal_elf_sym
.st_info
);
987 is_thumb
= (type
== STT_ARM_TFUNC
) || (type
== STT_ARM_16BIT
);
991 info
->bytes_per_chunk
= 4;
992 info
->display_endian
= little
? BFD_ENDIAN_LITTLE
: BFD_ENDIAN_BIG
;
996 status
= info
->read_memory_func (pc
, (bfd_byte
*) &b
[0], 4, info
);
997 if (status
!= 0 && is_thumb
)
999 info
->bytes_per_chunk
= 2;
1001 status
= info
->read_memory_func (pc
, (bfd_byte
*) b
, 2, info
);
1007 info
->memory_error_func (status
, pc
, info
);
1011 given
= (b
[0]) | (b
[1] << 8) | (b
[2] << 16) | (b
[3] << 24);
1015 status
= info
->read_memory_func
1016 (pc
& ~ 0x3, (bfd_byte
*) &b
[0], 4, info
);
1019 info
->memory_error_func (status
, pc
, info
);
1027 given
= (b
[2] << 8) | b
[3];
1029 status
= info
->read_memory_func
1030 ((pc
+ 4) & ~ 0x3, (bfd_byte
*) b
, 4, info
);
1033 info
->memory_error_func (status
, pc
+ 4, info
);
1037 given
|= (b
[0] << 24) | (b
[1] << 16);
1040 given
= (b
[0] << 8) | b
[1] | (b
[2] << 24) | (b
[3] << 16);
1043 given
= (b
[0] << 24) | (b
[1] << 16) | (b
[2] << 8) | (b
[3]);
1046 if (info
->flags
& INSN_HAS_RELOC
)
1047 /* If the instruction has a reloc associated with it, then
1048 the offset field in the instruction will actually be the
1049 addend for the reloc. (We are using REL type relocs).
1050 In such cases, we can ignore the pc when computing
1051 addresses, since the addend is not currently pc-relative. */
1055 status
= print_insn_thumb (pc
, info
, given
);
1057 status
= print_insn_arm (pc
, info
, given
);
1063 print_insn_big_arm (pc
, info
)
1065 struct disassemble_info
* info
;
1067 return print_insn (pc
, info
, false);
1071 print_insn_little_arm (pc
, info
)
1073 struct disassemble_info
* info
;
1075 return print_insn (pc
, info
, true);
1079 print_arm_disassembler_options (FILE * stream
)
1083 fprintf (stream
, _("\n\
1084 The following ARM specific disassembler options are supported for use with\n\
1085 the -M switch:\n"));
1087 for (i
= NUM_ARM_REGNAMES
; i
--;)
1088 fprintf (stream
, " reg-names-%s %*c%s\n",
1090 14 - strlen (regnames
[i
].name
), ' ',
1091 regnames
[i
].description
);
1093 fprintf (stream
, " force-thumb Assume all insns are Thumb insns\n");
1094 fprintf (stream
, " no-force-thumb Examine preceeding label to determine an insn's type\n\n");