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.
Barracudadiff -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.0 +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, 0xFF) > 0))
+{
+ error ("argument to %qE attribute larger than 0xFF",
+ 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.0 +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
&&