This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: how to embed an arbitrary opcode
Hi Richard,
Yay! Something I've wanted for a long time...
:-)
One question. What happens if .iword is used in Thumb mode, or .ishort
in ARM mode?
Well the new pseudos explicitly set the mapping state based on their
size, so for example if .iword were used in Thumb mode it would cause a
$a symbol to be emitted at point. Ie:
% cat fred.s
.text
.global foo
foo:
nop
.iword 0xe320f003
nop
.ishort 0x1234
nop
.thumb
.global bar
bar:
nop
.ishort 0x1234
nop
.iword 0xe320f003
nop
% as fred.s -o fred.o
% objdump -d fred.o
00000000 <foo>:
0: e1a00000 nop (mov r0,r0)
4: e320f003 wfi
8: e1a00000 nop (mov r0,r0)
c: 1234 asrs r4, r6, #8
e: e1a00000 nop (mov r0,r0)
00000012 <bar>:
12: 46c0 nop (mov r8, r8)
14: 1234 asrs r4, r6, #8
16: 46c0 nop (mov r8, r8)
18: e320f003 wfi
1c: 46c0 nop (mov r8, r8)
I think it would be better to just have .insn (or .inst),
which takes 32-bit numbers in ARM state and 16-bit numbers in thumb.
The assembler has to know what state it's in anyway in order to generate
the correct mapping symbol information.
I suspect that users are going to want to be able to use this mechanism
to insert arbitrary ARM or THUMB opcodes at arbitrary places without
regard to whether the assembler is currently in arm mode or thumb mode.
It would be quite easy to extend the patch however to add a third pseudo
op (.inst is fine by me) which chooses it size based on the current
mode. So attached is an improved version of the patch which does just
that. Let me know what you think and if everyone likes it I will check
it in. (Along with a testcase based on the fred.s file above).
Cheers
Nick
Index: gas/config/tc-arm.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-arm.c,v
retrieving revision 1.387
diff -c -3 -p -r1.387 tc-arm.c
*** gas/config/tc-arm.c 18 Jun 2009 16:36:02 -0000 1.387
--- gas/config/tc-arm.c 19 Jun 2009 14:15:35 -0000
*************** static void add_unwind_opcode (valueT, i
*** 2951,2979 ****
static void flush_pending_unwind (void);
/* Directives: Data. */
-
static void
! s_arm_elf_cons (int nbytes)
{
- expressionS exp;
-
- #ifdef md_flush_pending_output
- md_flush_pending_output ();
- #endif
-
- if (is_it_end_of_statement ())
- {
- demand_empty_rest_of_line ();
- return;
- }
-
- #ifdef md_cons_align
- md_cons_align (nbytes);
- #endif
-
- mapping_state (MAP_DATA);
do
{
int reloc;
char *base = input_line_pointer;
--- 2951,2962 ----
static void flush_pending_unwind (void);
/* Directives: Data. */
static void
! arm_elf_cons_worker (int nbytes)
{
do
{
+ expressionS exp;
int reloc;
char *base = input_line_pointer;
*************** s_arm_elf_cons (int nbytes)
*** 2984,2989 ****
--- 2967,2973 ----
else
{
char *before_reloc = input_line_pointer;
+
reloc = parse_reloc (&input_line_pointer);
if (reloc == -1)
{
*************** s_arm_elf_cons (int nbytes)
*** 3017,3022 ****
--- 3001,3007 ----
char *p = input_line_pointer;
int offset;
char *save_buf = alloca (input_line_pointer - base);
+
memcpy (save_buf, base, input_line_pointer - base);
memmove (base + (input_line_pointer - before_reloc),
base, before_reloc - base);
*************** s_arm_elf_cons (int nbytes)
*** 3040,3045 ****
--- 3025,3064 ----
demand_empty_rest_of_line ();
}
+ static void
+ s_arm_elf_cons (int nbytes)
+ {
+ if (is_it_end_of_statement ())
+ {
+ demand_empty_rest_of_line ();
+ return;
+ }
+
+ md_cons_align (nbytes); /* Sets mapping state to MAPPING_DATA. */
+
+ arm_elf_cons_worker (nbytes);
+ }
+
+ /* Like s_arm_elf_cons but do not use md_cons_align and
+ set the mapping state to MAP_ARM (if nbytes == 4) or
+ MAP_THUMB (if nbytes == 2) or neither (if nbytes == 0). */
+
+ static void
+ s_arm_elf_iword (int nbytes)
+ {
+ if (is_it_end_of_statement ())
+ {
+ demand_empty_rest_of_line ();
+ return;
+ }
+
+ if (nbytes)
+ mapping_state (nbytes == 4 ? MAP_ARM : MAP_THUMB);
+ else
+ nbytes = mapstate == MAP_ARM ? 4 : 2;
+
+ arm_elf_cons_worker (nbytes);
+ }
/* Parse a .rel31 directive. */
*************** const pseudo_typeS md_pseudo_table[] =
*** 3958,3966 ****
{ "object_arch", s_arm_object_arch, 0 },
{ "fpu", s_arm_fpu, 0 },
#ifdef OBJ_ELF
! { "word", s_arm_elf_cons, 4 },
! { "long", s_arm_elf_cons, 4 },
! { "rel31", s_arm_rel31, 0 },
{ "fnstart", s_arm_unwind_fnstart, 0 },
{ "fnend", s_arm_unwind_fnend, 0 },
{ "cantunwind", s_arm_unwind_cantunwind, 0 },
--- 3977,3988 ----
{ "object_arch", s_arm_object_arch, 0 },
{ "fpu", s_arm_fpu, 0 },
#ifdef OBJ_ELF
! { "word", s_arm_elf_cons, 4 },
! { "long", s_arm_elf_cons, 4 },
! { "inst", s_arm_elf_iword, 0 },
! { "ishort", s_arm_elf_iword, 2 },
! { "iword", s_arm_elf_iword, 4 },
! { "rel31", s_arm_rel31, 0 },
{ "fnstart", s_arm_unwind_fnstart, 0 },
{ "fnend", s_arm_unwind_fnend, 0 },
{ "cantunwind", s_arm_unwind_cantunwind, 0 },
Index: gas/doc/c-arm.texi
===================================================================
RCS file: /cvs/src/src/gas/doc/c-arm.texi,v
retrieving revision 1.56
diff -c -3 -p -r1.56 c-arm.texi
*** gas/doc/c-arm.texi 2 Apr 2009 09:43:56 -0000 1.56
--- gas/doc/c-arm.texi 19 Jun 2009 14:15:35 -0000
*************** Must be preceded by a @code{.personality
*** 564,569 ****
--- 564,595 ----
directive.
@c IIIIIIIIIIIIIIIIIIIIIIIIII
+
+ @cindex @code{.inst} directive, ARM
+ @item .inst @var{expression} [, @var{expression}]*
+ Inserts one or more comma separated expressions into the output stream
+ without changing the mapping state (@pxref{ARM Mapping Symbols}). The
+ size of the values inserted depends upon whether the assembler is
+ currently in ARM mode (32-bit values are inserted) or Thumb mode
+ (16-bit values are inserted) as set by the @var{.code} directive.
+ This directive is only supported in ELF based ARM toolchains.
+
+ @cindex @code{.ishort} directive, ARM
+ @item .ishort @var{expression} [, @var{expression}]*
+ Inserts one or more comma separated expressions into the output stream
+ as 16-bit values and marks them as being THUMB instructions. This
+ directive is only supported in ELF based ARM toolchains. Note: the
+ generic GAS directive @code{.short} does the same thing, but it marks
+ the values as being data not instructions.
+
+ @cindex @code{.iword} directive, ARM
+ @item .iword @var{expression} [, @var{expression}]*
+ Inserts one or more comma separated expressions into the output stream
+ as 32-bit values and marks them as being ARM instructions. This
+ directive is only supported in ELF based ARM toolchains. Note: the
+ generic GAS directive @code{.word} does the same thing, but it marks
+ the values as being data not instructions.
+
@c JJJJJJJJJJJJJJJJJJJJJJJJJJ
@c KKKKKKKKKKKKKKKKKKKKKKKKKK
@c LLLLLLLLLLLLLLLLLLLLLLLLLL