Hello!
I'm new to GCC internals, but I'm using GCC for couple of years.
Yesterday I found that GCC does not support calling SWI routines from C/C++
code.
For example, in other ARM-targeted compiliers developer can use such syntax
for function prototype:
In ARM IAR:
#pragma swi_number=0x15
int some_call(int, int);
In RVDS:
__swi(0x15) int some_call(int, int);
And then just call function as usual:
a = some_call(5, 8);
GCC lacks this feauture, so I've decided to go on Free Software way - if your
need something, implement it yourself =)
I can't write any testsuite, because I don't know how to do it, sorry. I
tested some programs written for IAR, they compiled and launched successfully.
I've also tested some programs with functions that don't use this attribute -
they was unaffected by this patch. So I decided to send it to this mailing
list.
Changelog and patch included in attachment.
I tested cross-compiling, host=i686-pc-linux-gnu and host=x86_64-pc-linux-gnu,
target=arm-linux-gnueabi. Works stable and fine.
Barracuda
diff -aur sources/gcc-4.5.1/gcc/config/arm//arm.c gcc-4.5.1/gcc/config/arm//arm.c
--- sources/gcc-4.5.1/gcc/config/arm//arm.c 2010-07-12 20:05:41.000000000 +0600
+++ gcc-4.5.1/gcc/config/arm//arm.c 2012-02-21 04:24:13.295235261 +0600
@@ -225,6 +225,7 @@
static void arm_trampoline_init (rtx, tree, rtx);
static rtx arm_trampoline_adjust_address (rtx);
+static tree arm_handle_swi_attribute (tree *, tree, tree, int, bool *);
/* Table of machine attributes. */
static const struct attribute_spec arm_attribute_table[] =
@@ -243,6 +246,7 @@
{ "isr", 0, 1, false, false, false, arm_handle_isr_attribute },
{ "interrupt", 0, 1, false, false, false, arm_handle_isr_attribute },
{ "naked", 0, 0, true, false, false, arm_handle_fndecl_attribute },
+ { "swi", 1, 1, false, false, false, arm_handle_swi_attribute },
#ifdef ARM_PE
/* ARM/PE has three new attributes:
interfacearm - ?
@@ -4595,6 +4601,47 @@
return NULL_TREE;
}
+static tree
+arm_handle_swi_attribute (tree *node, tree name, tree args, int flags,
+ bool *no_add_attrs)
+{
+ if (DECL_P (*node))
+ {
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute only applies to functions",
+ name);
+ *no_add_attrs = true;
+ } else {
+ tree cst = TREE_VALUE (args);
+ if (TREE_CODE (cst) != INTEGER_CST)
+ {
+ error ("%qE attribute requires an integer constant argument",
+ name);
+ *no_add_attrs = true;
+ }
+ else if (TARGET_ARM && (compare_tree_int (cst, 0xFFFFFF) > 0))
+ {
+ error ("argument to %qE attribute larger than 0xFFFFFF",
+ name);
+ *no_add_attrs = true;
+ }
+ else if (TARGET_THUMB && (compare_tree_int (cst, 0xFF) > 0))
+ {
+ error ("argument to %qE attribute larger than 0xFF",
+ name);
+ *no_add_attrs = true;
+ }
+ }
+ } else {
+ warning (OPT_Wattributes,
+ "%qE attribute can be applied only to function prototype");
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
/* Handle a "pcs" attribute; arguments as in struct
attribute_spec.handler. */
static tree
@@ -4768,6 +4821,52 @@
return TARGET_LONG_CALLS;
}
+bool
+arm_is_swicall (tree decl)
+{
+ tree attrs;
+ tree a;
+
+ if (!decl)
+ {
+ return false;
+ }
+
+ attrs = DECL_ATTRIBUTES ( decl);
+ a = lookup_attribute ("swi", attrs);
+ if (a == NULL_TREE)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+const char *
+output_swicall (tree decl)
+{
+ tree attrs;
+ tree a;
+ tree cst;
+ int value;
+ char *buf = ggc_alloc_cleared (32);
+
+ attrs = DECL_ATTRIBUTES (decl);
+ a = lookup_attribute ("swi", attrs);
+ if (TREE_VALUE (a) == NULL_TREE)
+ return "ERROR";
+
+ cst = TREE_VALUE (TREE_VALUE (a));
+ if (TREE_CODE (cst) != INTEGER_CST)
+ return "ERROR1";
+
+ value = TREE_INT_CST_LOW (cst);
+
+ snprintf (buf, 32, "swi%%?\t%d", value);
+
+ return buf;
+}
+
/* Return nonzero if it is ok to make a tail-call to DECL. */
static bool
arm_function_ok_for_sibcall (tree decl, tree exp)
diff -aur sources/gcc-4.5.1/gcc/config/arm//arm.md gcc-4.5.1/gcc/config/arm//arm.md
--- sources/gcc-4.5.1/gcc/config/arm//arm.md 2010-07-31 04:35:40.000000000 +0600
+++ gcc-4.5.1/gcc/config/arm//arm.md 2012-02-21 04:20:46.846224042 +0600
@@ -8646,7 +8646,11 @@
&& !arm_is_long_call_p (SYMBOL_REF_DECL (operands[1]))"
"*
{
- return NEED_PLT_RELOC ? \"bl%?\\t%a1(PLT)\" : \"bl%?\\t%a1\";
+ bool is_swi = arm_is_swicall (SYMBOL_REF_DECL (operands[1]));
+ if (is_swi)
+ return output_swicall (SYMBOL_REF_DECL (operands[1]));
+ else
+ return NEED_PLT_RELOC ? \"bl%?\\t%a1(PLT)\" : \"bl%?\\t%a1\";
}"
[(set_attr "type" "call")]
)
@@ -8673,7 +8678,14 @@
"TARGET_THUMB
&& GET_CODE (operands[1]) == SYMBOL_REF
&& !arm_is_long_call_p (SYMBOL_REF_DECL (operands[1]))"
- "bl\\t%a1"
+ "*
+ {
+ bool is_swi = arm_is_swicall (SYMBOL_REF_DECL (operands[1]));
+ if (is_swi)
+ return output_swicall (SYMBOL_REF_DECL (operands[1]));
+ else
+ return \"bl\\t%a1\";
+ }"
[(set_attr "length" "4")
(set_attr "type" "call")]
)
diff -aur sources/gcc-4.5.1/gcc/config/arm//arm-protos.h gcc-4.5.1/gcc/config/arm//arm-protos.h
--- sources/gcc-4.5.1/gcc/config/arm//arm-protos.h 2010-07-05 18:45:19.000000000 +0600
+++ gcc-4.5.1/gcc/config/arm//arm-protos.h 2012-02-21 04:04:38.185415081 +0600
@@ -120,6 +120,7 @@
extern void arm_emit_call_insn (rtx, rtx);
extern const char *output_call (rtx *);
extern const char *output_call_mem (rtx *);
+extern const char *output_swicall (tree decl);
void arm_emit_movpair (rtx, rtx);
extern const char *output_mov_long_double_fpa_from_arm (rtx *);
extern const char *output_mov_long_double_arm_from_fpa (rtx *);
@@ -141,6 +144,7 @@
extern void arm_final_prescan_insn (rtx);
extern int arm_debugger_arg_offset (int, rtx);
extern bool arm_is_long_call_p (tree);
+extern bool arm_is_swicall (tree);
extern int arm_emit_vector_const (FILE *, rtx);
extern void arm_emit_fp16_const (rtx c);
extern const char * arm_output_load_gr (rtx *);
2012-02-21 Labutin Ivan <barracud...@bk.ru>
* gcc/config/arm/arm.c: Added support for __attribute__ ((swi(x))).
With this, you can write function prototype:
int some_sys_call (int, char*) __attribute__ ((swi(0x15)));
Now, if you call it:
a = some_sys_call (5, "test");
it will produce following assembler output:
...
MOV R1, #test_adr
MOV R0, #5
SWI 0x15
...
This is an analogue of
#pragma swi_number=0x15 int some_sys_call (int, char *);
or
__swi(0x15) int some_sys_call (int, char*);
in other ARM-targeted compiliers.
* gcc/config/arm.md: Likewise.
* gcc/config/arm-protos.h: Likewise.