diff -aur gcc-4.5.2.orig/gcc/config/arm/arm.c gcc-4.5.2/gcc/config/arm/arm.c
--- gcc-4.5.2.orig/gcc/config/arm/arm.c	2010-09-02 19:05:30.000000000 +0600
+++ gcc-4.5.2/gcc/config/arm/arm.c	2012-02-22 06:51:31.405545451 +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,46 @@
   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))
+            {
+              warning (OPT_Wattributes,
+                       "argument to %qE attribute larger than 0xFF", name);
+            }
+        }
+    } else {
+      warning (OPT_Wattributes,
+               "%qE attribute can be applied only to function prototype", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
 /* Handle a "pcs" attribute; arguments as in struct
    attribute_spec.handler.  */
 static tree
@@ -4768,6 +4820,67 @@
   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_atomic (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);
+
+  if (TARGET_ARM)
+    {
+      snprintf (buf, 32, "swi%%?\t%d", value);
+    } else {
+      /*
+        SIEMENS-specific
+        Thumb routines normally can call only SWI 0x00 - 0xFF
+        To call 0x100 - 0xFFFF we use a hack - SWI 0xCC with
+        real SWI number after it.  Handler of SWI will load
+        real SWI number and then properly ajust LR register.
+      */
+      if (value > 0xFF)
+        {
+          snprintf (buf, 32, "swi\t0xCC\n\t.short\t%d", value);
+        }
+      else
+        {
+          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)
@@ -4792,6 +4910,10 @@
   if (arm_is_long_call_p (decl))
     return false;
 
+  /* Cannot tail-call to SWI functions for obvious reasons.  */
+  if (arm_is_swicall (decl))
+    return false;
+
   /* If we are interworking and the function is not declared static
      then we can't tail-call it unless we know that it exists in this
      compilation unit (since it might be a Thumb routine).  */
diff -aur gcc-4.5.2.orig/gcc/config/arm/arm.md gcc-4.5.2/gcc/config/arm/arm.md
--- gcc-4.5.2.orig/gcc/config/arm/arm.md	2010-09-20 21:27:13.000000000 +0600
+++ gcc-4.5.2/gcc/config/arm/arm.md	2012-02-22 06:52:12.729546052 +0600
@@ -8630,7 +8630,11 @@
    && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[0]))"
   "*
   {
-    return NEED_PLT_RELOC ? \"bl%?\\t%a0(PLT)\" : \"bl%?\\t%a0\";
+    bool is_swi = arm_is_swicall (SYMBOL_REF_DECL (operands[0]));
+    if (is_swi)
+      return output_swicall (SYMBOL_REF_DECL (operands[0]));
+    else
+      return NEED_PLT_RELOC ? \"bl%?\\t%a0(PLT)\" : \"bl%?\\t%a0\";
   }"
   [(set_attr "type" "call")]
 )
@@ -8646,7 +8651,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")]
 )
@@ -8659,7 +8669,14 @@
   "TARGET_THUMB
    && GET_CODE (operands[0]) == SYMBOL_REF
    && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[0]))"
-  "bl\\t%a0"
+  "*
+  {
+    bool is_swi = arm_is_swicall (SYMBOL_REF_DECL (operands[0]));
+    if (is_swi)
+      return output_swicall (SYMBOL_REF_DECL (operands[0]));
+    else
+      return \"bl\\t%a0\";
+  }"
   [(set_attr "length" "4")
    (set_attr "type" "call")]
 )
@@ -8673,7 +8690,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 gcc-4.5.2.orig/gcc/config/arm/arm-protos.h gcc-4.5.2/gcc/config/arm/arm-protos.h
--- gcc-4.5.2.orig/gcc/config/arm/arm-protos.h	2010-07-05 18:45:19.000000000 +0600
+++ gcc-4.5.2/gcc/config/arm/arm-protos.h	2012-02-22 06:51:44.233545647 +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 *);
