1 /* Instruction printing code for the ARM
2 Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
3 Free Software Foundation, Inc.
4 Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
5 Modification by James G. Smith (jsmith@cygnus.co.uk)
7 This file is part of libopcodes.
9 This program is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 2 of the License, or (at your option)
14 This program is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
27 #include "coff/internal.h"
31 /* FIXME: This shouldn't be done here */
33 #include "elf/internal.h"
37 #define streq(a,b) (strcmp ((a), (b)) == 0)
41 #define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0)
45 #define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0])
48 static char * arm_conditional
[] =
49 {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
50 "hi", "ls", "ge", "lt", "gt", "le", "", "nv"};
55 const char * description
;
56 const char * reg_names
[16];
60 static arm_regname regnames
[] =
62 { "raw" , "Select raw register names",
63 { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}},
64 { "gcc", "Select register names used by GCC",
65 { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc" }},
66 { "std", "Select register names used in ARM's ISA documentation",
67 { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc" }},
68 { "apcs", "Select register names used in the APCS",
69 { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "sl", "fp", "ip", "sp", "lr", "pc" }},
70 { "atpcs", "Select register names used in the ATPCS",
71 { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "IP", "SP", "LR", "PC" }},
72 { "special-atpcs", "Select special register names used in the ATPCS",
73 { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }}
76 /* Default to GCC register name set. */
77 static unsigned int regname_selected
= 1;
79 #define NUM_ARM_REGNAMES NUM_ELEM (regnames)
80 #define arm_regnames regnames[regname_selected].reg_names
82 static boolean force_thumb
= false;
84 static char * arm_fp_const
[] =
85 {"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"};
87 static char * arm_shift
[] =
88 {"lsl", "lsr", "asr", "ror"};
90 /* Forward declarations. */
91 static void arm_decode_shift
PARAMS ((long, fprintf_ftype
, void *));
92 static int print_insn_arm
PARAMS ((bfd_vma
, struct disassemble_info
*, long));
93 static int print_insn_thumb
PARAMS ((bfd_vma
, struct disassemble_info
*, long));
94 static void parse_disassembler_options
PARAMS ((char *));
95 static int print_insn
PARAMS ((bfd_vma
, struct disassemble_info
*, boolean
));
96 int get_arm_regname_num_options (void);
97 int set_arm_regname_option (int option
);
98 int get_arm_regnames (int option
, const char **setname
,
99 const char **setdescription
,
100 const char ***register_names
);
104 get_arm_regname_num_options (void)
106 return NUM_ARM_REGNAMES
;
110 set_arm_regname_option (int option
)
112 int old
= regname_selected
;
113 regname_selected
= option
;
118 get_arm_regnames (int option
, const char **setname
,
119 const char **setdescription
,
120 const char ***register_names
)
122 *setname
= regnames
[option
].name
;
123 *setdescription
= regnames
[option
].description
;
124 *register_names
= regnames
[option
].reg_names
;
129 arm_decode_shift (given
, func
, stream
)
134 func (stream
, "%s", arm_regnames
[given
& 0xf]);
136 if ((given
& 0xff0) != 0)
138 if ((given
& 0x10) == 0)
140 int amount
= (given
& 0xf80) >> 7;
141 int shift
= (given
& 0x60) >> 5;
147 func (stream
, ", rrx");
154 func (stream
, ", %s #%d", arm_shift
[shift
], amount
);
157 func (stream
, ", %s %s", arm_shift
[(given
& 0x60) >> 5],
158 arm_regnames
[(given
& 0xf00) >> 8]);
162 /* Print one instruction from PC on INFO->STREAM.
163 Return the size of the instruction (always 4 on ARM). */
165 print_insn_arm (pc
, info
, given
)
167 struct disassemble_info
* info
;
170 struct arm_opcode
* insn
;
171 void * stream
= info
->stream
;
172 fprintf_ftype func
= info
->fprintf_func
;
174 for (insn
= arm_opcodes
; insn
->assembler
; insn
++)
176 if ((given
& insn
->mask
) == insn
->value
)
180 for (c
= insn
->assembler
; *c
; c
++)
191 if (((given
& 0x000f0000) == 0x000f0000)
192 && ((given
& 0x02000000) == 0))
194 int offset
= given
& 0xfff;
196 func (stream
, "[pc");
198 if (given
& 0x01000000)
200 if ((given
& 0x00800000) == 0)
204 func (stream
, ", #%d]", offset
);
208 /* Cope with the possibility of write-back
209 being used. Probably a very dangerous thing
210 for the programmer to do, but who are we to
212 if (given
& 0x00200000)
218 func (stream
, "], #%d", offset
);
220 offset
= pc
+ 8; /* ie ignore the offset. */
223 func (stream
, "\t; ");
224 info
->print_address_func (offset
, info
);
229 arm_regnames
[(given
>> 16) & 0xf]);
230 if ((given
& 0x01000000) != 0)
232 if ((given
& 0x02000000) == 0)
234 int offset
= given
& 0xfff;
236 func (stream
, ", %s#%d",
237 (((given
& 0x00800000) == 0)
238 ? "-" : ""), offset
);
242 func (stream
, ", %s",
243 (((given
& 0x00800000) == 0)
245 arm_decode_shift (given
, func
, stream
);
249 ((given
& 0x00200000) != 0) ? "!" : "");
253 if ((given
& 0x02000000) == 0)
255 int offset
= given
& 0xfff;
257 func (stream
, "], %s#%d",
258 (((given
& 0x00800000) == 0)
259 ? "-" : ""), offset
);
265 func (stream
, "], %s",
266 (((given
& 0x00800000) == 0)
268 arm_decode_shift (given
, func
, stream
);
275 if ((given
& 0x004f0000) == 0x004f0000)
277 /* PC relative with immediate offset. */
278 int offset
= ((given
& 0xf00) >> 4) | (given
& 0xf);
280 if ((given
& 0x00800000) == 0)
283 func (stream
, "[pc, #%d]\t; ", offset
);
285 (*info
->print_address_func
)
286 (offset
+ pc
+ 8, info
);
291 arm_regnames
[(given
>> 16) & 0xf]);
292 if ((given
& 0x01000000) != 0)
295 if ((given
& 0x00400000) == 0x00400000)
298 int offset
= ((given
& 0xf00) >> 4) | (given
& 0xf);
300 func (stream
, ", %s#%d",
301 (((given
& 0x00800000) == 0)
302 ? "-" : ""), offset
);
307 func (stream
, ", %s%s",
308 (((given
& 0x00800000) == 0)
310 arm_regnames
[given
& 0xf]);
314 ((given
& 0x00200000) != 0) ? "!" : "");
319 if ((given
& 0x00400000) == 0x00400000)
322 int offset
= ((given
& 0xf00) >> 4) | (given
& 0xf);
324 func (stream
, "], %s#%d",
325 (((given
& 0x00800000) == 0)
326 ? "-" : ""), offset
);
333 func (stream
, "], %s%s",
334 (((given
& 0x00800000) == 0)
336 arm_regnames
[given
& 0xf]);
343 (*info
->print_address_func
)
344 (BDISP (given
) * 4 + pc
+ 8, info
);
349 arm_conditional
[(given
>> 28) & 0xf]);
358 for (reg
= 0; reg
< 16; reg
++)
359 if ((given
& (1 << reg
)) != 0)
364 func (stream
, "%s", arm_regnames
[reg
]);
371 if ((given
& 0x02000000) != 0)
373 int rotate
= (given
& 0xf00) >> 7;
374 int immed
= (given
& 0xff);
375 immed
= (((immed
<< (32 - rotate
))
376 | (immed
>> rotate
)) & 0xffffffff);
377 func (stream
, "#%d\t; 0x%x", immed
, immed
);
380 arm_decode_shift (given
, func
, stream
);
384 if ((given
& 0x0000f000) == 0x0000f000)
389 if ((given
& 0x01200000) == 0x00200000)
394 if ((given
& 0x00000020) == 0x00000020)
401 func (stream
, "[%s", arm_regnames
[(given
>> 16) & 0xf]);
402 if ((given
& 0x01000000) != 0)
404 int offset
= given
& 0xff;
406 func (stream
, ", %s#%d]%s",
407 ((given
& 0x00800000) == 0 ? "-" : ""),
409 ((given
& 0x00200000) != 0 ? "!" : ""));
415 int offset
= given
& 0xff;
417 func (stream
, "], %s#%d",
418 ((given
& 0x00800000) == 0 ? "-" : ""),
426 /* Print ARM V5 BLX(1) address: pc+25 bits. */
431 if (given
& 0x00800000)
432 /* Is signed, hi bits should be ones. */
433 offset
= (-1) ^ 0x00ffffff;
435 /* Offset is (SignExtend(offset field)<<2). */
436 offset
+= given
& 0x00ffffff;
438 address
= offset
+ pc
+ 8;
440 if (given
& 0x01000000)
441 /* H bit allows addressing to 2-byte boundaries. */
444 info
->print_address_func (address
, info
);
461 switch (given
& 0x00408000)
478 switch (given
& 0x00080080)
490 func (stream
, _("<illegal precision>"));
495 switch (given
& 0x00408000)
512 switch (given
& 0x60)
528 case '0': case '1': case '2': case '3': case '4':
529 case '5': case '6': case '7': case '8': case '9':
531 int bitstart
= *c
++ - '0';
533 while (*c
>= '0' && *c
<= '9')
534 bitstart
= (bitstart
* 10) + *c
++ - '0';
541 while (*c
>= '0' && *c
<= '9')
542 bitend
= (bitend
* 10) + *c
++ - '0';
553 reg
= given
>> bitstart
;
554 reg
&= (2 << (bitend
- bitstart
)) - 1;
556 func (stream
, "%s", arm_regnames
[reg
]);
563 reg
= given
>> bitstart
;
564 reg
&= (2 << (bitend
- bitstart
)) - 1;
566 func (stream
, "%d", reg
);
573 reg
= given
>> bitstart
;
574 reg
&= (2 << (bitend
- bitstart
)) - 1;
576 func (stream
, "0x%08x", reg
);
578 /* Some SWI instructions have special
580 if ((given
& 0x0fffffff) == 0x0FF00000)
581 func (stream
, "\t; IMB");
582 else if ((given
& 0x0fffffff) == 0x0FF00001)
583 func (stream
, "\t; IMBRange");
590 reg
= given
>> bitstart
;
591 reg
&= (2 << (bitend
- bitstart
)) - 1;
593 func (stream
, "%01x", reg
& 0xf);
600 reg
= given
>> bitstart
;
601 reg
&= (2 << (bitend
- bitstart
)) - 1;
605 arm_fp_const
[reg
& 7]);
607 func (stream
, "f%d", reg
);
617 if ((given
& (1 << bitstart
)) == 0)
618 func (stream
, "%c", *c
);
622 if ((given
& (1 << bitstart
)) != 0)
623 func (stream
, "%c", *c
);
627 if ((given
& (1 << bitstart
)) != 0)
628 func (stream
, "%c", *c
++);
630 func (stream
, "%c", *++c
);
643 func (stream
, "%c", *c
);
651 /* Print one instruction from PC on INFO->STREAM.
652 Return the size of the instruction. */
654 print_insn_thumb (pc
, info
, given
)
656 struct disassemble_info
* info
;
659 struct thumb_opcode
* insn
;
660 void * stream
= info
->stream
;
661 fprintf_ftype func
= info
->fprintf_func
;
663 for (insn
= thumb_opcodes
; insn
->assembler
; insn
++)
665 if ((given
& insn
->mask
) == insn
->value
)
667 char * c
= insn
->assembler
;
669 /* Special processing for Thumb 2 instruction BL sequence: */
670 if (!*c
) /* Check for empty (not NULL) assembler string. */
674 info
->bytes_per_chunk
= 4;
675 info
->bytes_per_line
= 4;
677 offset
= BDISP23 (given
);
679 if ((given
& 0x10000000) == 0)
681 func (stream
, "blx\t");
683 /* The spec says that bit 1 of the branch's destination
684 address comes from bit 1 of the instruction's
685 address and not from the offset in the instruction. */
688 /* func (stream, "*malformed!* "); */
692 offset
|= ((pc
& 0x2) >> 1);
695 func (stream
, "bl\t");
697 info
->print_address_func (offset
* 2 + pc
+ 4, info
);
702 info
->bytes_per_chunk
= 2;
703 info
->bytes_per_line
= 4;
724 reg
= (given
>> 3) & 0x7;
725 if (given
& (1 << 6))
728 func (stream
, "%s", arm_regnames
[reg
]);
737 if (given
& (1 << 7))
740 func (stream
, "%s", arm_regnames
[reg
]);
746 arm_conditional
[(given
>> 8) & 0xf]);
750 if (given
& (1 << 8))
754 if (*c
== 'O' && (given
& (1 << 8)))
764 /* It would be nice if we could spot
765 ranges, and generate the rS-rE format: */
766 for (reg
= 0; (reg
< 8); reg
++)
767 if ((given
& (1 << reg
)) != 0)
772 func (stream
, "%s", arm_regnames
[reg
]);
780 func (stream
, arm_regnames
[14] /* "lr" */);
787 func (stream
, arm_regnames
[15] /* "pc" */);
795 case '0': case '1': case '2': case '3': case '4':
796 case '5': case '6': case '7': case '8': case '9':
798 int bitstart
= *c
++ - '0';
801 while (*c
>= '0' && *c
<= '9')
802 bitstart
= (bitstart
* 10) + *c
++ - '0';
811 while (*c
>= '0' && *c
<= '9')
812 bitend
= (bitend
* 10) + *c
++ - '0';
815 reg
= given
>> bitstart
;
816 reg
&= (2 << (bitend
- bitstart
)) - 1;
820 func (stream
, "%s", arm_regnames
[reg
]);
824 func (stream
, "%d", reg
);
828 func (stream
, "%d", reg
<< 1);
832 func (stream
, "%d", reg
<< 2);
836 /* PC-relative address -- the bottom two
837 bits of the address are dropped
838 before the calculation. */
839 info
->print_address_func
840 (((pc
+ 4) & ~3) + (reg
<< 2), info
);
844 func (stream
, "0x%04x", reg
);
848 reg
= ((reg
^ (1 << bitend
)) - (1 << bitend
));
849 func (stream
, "%d", reg
);
853 reg
= ((reg
^ (1 << bitend
)) - (1 << bitend
));
854 (*info
->print_address_func
)
855 (reg
* 2 + pc
+ 4, info
);
866 if ((given
& (1 << bitstart
)) != 0)
867 func (stream
, "%c", *c
);
872 if ((given
& (1 << bitstart
)) != 0)
873 func (stream
, "%c", *c
++);
875 func (stream
, "%c", *++c
);
889 func (stream
, "%c", *c
);
900 /* Parse an individual disassembler option. */
902 parse_arm_disassembler_option (option
)
908 if (strneq (option
, "reg-names-", 10))
914 for (i
= NUM_ARM_REGNAMES
; i
--;)
915 if (streq (option
, regnames
[i
].name
))
917 regname_selected
= i
;
922 fprintf (stderr
, _("Unrecognised register name set: %s\n"), option
);
924 else if (streq (option
, "force-thumb"))
926 else if (streq (option
, "no-force-thumb"))
929 fprintf (stderr
, _("Unrecognised disassembler option: %s\n"), option
);
934 /* Parse the string of disassembler options, spliting it at whitespaces. */
936 parse_disassembler_options (options
)
946 space
= strchr (options
, ' ');
951 parse_arm_disassembler_option (options
);
956 parse_arm_disassembler_option (options
);
961 /* NOTE: There are no checks in these routines that
962 the relevant number of data bytes exist. */
964 print_insn (pc
, info
, little
)
966 struct disassemble_info
* info
;
974 if (info
->disassembler_options
)
976 parse_disassembler_options (info
->disassembler_options
);
978 /* To avoid repeated parsing of these options, we remove them here. */
979 info
->disassembler_options
= NULL
;
982 is_thumb
= force_thumb
;
984 if (!is_thumb
&& info
->symbols
!= NULL
)
986 if (bfd_asymbol_flavour (*info
->symbols
) == bfd_target_coff_flavour
)
988 coff_symbol_type
* cs
;
990 cs
= coffsymbol (*info
->symbols
);
991 is_thumb
= ( cs
->native
->u
.syment
.n_sclass
== C_THUMBEXT
992 || cs
->native
->u
.syment
.n_sclass
== C_THUMBSTAT
993 || cs
->native
->u
.syment
.n_sclass
== C_THUMBLABEL
994 || cs
->native
->u
.syment
.n_sclass
== C_THUMBEXTFUNC
995 || cs
->native
->u
.syment
.n_sclass
== C_THUMBSTATFUNC
);
997 else if (bfd_asymbol_flavour (*info
->symbols
) == bfd_target_elf_flavour
)
999 elf_symbol_type
* es
;
1002 es
= *(elf_symbol_type
**)(info
->symbols
);
1003 type
= ELF_ST_TYPE (es
->internal_elf_sym
.st_info
);
1005 is_thumb
= (type
== STT_ARM_TFUNC
) || (type
== STT_ARM_16BIT
);
1009 info
->bytes_per_chunk
= 4;
1010 info
->display_endian
= little
? BFD_ENDIAN_LITTLE
: BFD_ENDIAN_BIG
;
1014 status
= info
->read_memory_func (pc
, (bfd_byte
*) &b
[0], 4, info
);
1015 if (status
!= 0 && is_thumb
)
1017 info
->bytes_per_chunk
= 2;
1019 status
= info
->read_memory_func (pc
, (bfd_byte
*) b
, 2, info
);
1025 info
->memory_error_func (status
, pc
, info
);
1029 given
= (b
[0]) | (b
[1] << 8) | (b
[2] << 16) | (b
[3] << 24);
1033 status
= info
->read_memory_func
1034 (pc
& ~ 0x3, (bfd_byte
*) &b
[0], 4, info
);
1037 info
->memory_error_func (status
, pc
, info
);
1045 given
= (b
[2] << 8) | b
[3];
1047 status
= info
->read_memory_func
1048 ((pc
+ 4) & ~ 0x3, (bfd_byte
*) b
, 4, info
);
1051 info
->memory_error_func (status
, pc
+ 4, info
);
1055 given
|= (b
[0] << 24) | (b
[1] << 16);
1058 given
= (b
[0] << 8) | b
[1] | (b
[2] << 24) | (b
[3] << 16);
1061 given
= (b
[0] << 24) | (b
[1] << 16) | (b
[2] << 8) | (b
[3]);
1064 if (info
->flags
& INSN_HAS_RELOC
)
1065 /* If the instruction has a reloc associated with it, then
1066 the offset field in the instruction will actually be the
1067 addend for the reloc. (We are using REL type relocs).
1068 In such cases, we can ignore the pc when computing
1069 addresses, since the addend is not currently pc-relative. */
1073 status
= print_insn_thumb (pc
, info
, given
);
1075 status
= print_insn_arm (pc
, info
, given
);
1081 print_insn_big_arm (pc
, info
)
1083 struct disassemble_info
* info
;
1085 return print_insn (pc
, info
, false);
1089 print_insn_little_arm (pc
, info
)
1091 struct disassemble_info
* info
;
1093 return print_insn (pc
, info
, true);
1097 print_arm_disassembler_options (FILE * stream
)
1101 fprintf (stream
, _("\n\
1102 The following ARM specific disassembler options are supported for use with\n\
1103 the -M switch:\n"));
1105 for (i
= NUM_ARM_REGNAMES
; i
--;)
1106 fprintf (stream
, " reg-names-%s %*c%s\n",
1108 14 - strlen (regnames
[i
].name
), ' ',
1109 regnames
[i
].description
);
1111 fprintf (stream
, " force-thumb Assume all insns are Thumb insns\n");
1112 fprintf (stream
, " no-force-thumb Examine preceeding label to determine an insn's type\n\n");