Сделал патч для того, чтобы gcc поддерживал __attribute__((naked)) на платформе i386. Тупо генерирует фунцкию без пролога и эпилога (в т.ч. и без ret, как и в большинстве компиляторов). Возможно, кому-нибудь пригодится, например, для создания хендлеров для прерываний.
Особенности:
1. внутри naked функций нельзя вызывать функции с параметрами, передающимися через стек, поскольку gcc кладет параметры в положительном смещении от esp. Например, нельзя:
Код:
void f2(int k)
{
kprintf("%i\n", k);
}
__attribute__((naked)) void f1()
{
f2(3);
asm("ret");
}
при передаче параметра 3 в функцию f2 gcc затрет код возврата... зато, можно f2 объявить как __attribute__((regparm(1))) и все будет нормально (только при этом необходимо применить оптимизацию, например, в виде -O2 или -Os).
2. нельзя применять -fomit-frame-pointer, поскольку в таком случае и локальные переменные окажутся выше esp.
Решение проблем:
- для прерываний создать отдельный модуль, который будет компилироваться без -fomit-frame-pointer.
- передавать параметры через регистры во все функции которые вызываются из naked функций, и использовать при этом -O2.
P.S. если кто может помочь с ключом компилятора, чтоб параметры в функцию пушились, буду благодарен. ))
P.P.S. файлом патч выложить не удалось, поэтому выкладываю текстом:
(применение: в директории gcc-4.5.1: patch -Np1 -i ../gcc-4.5.1_naked.patch)
Код:
diff -cr gcc.orig/gcc/config/i386/i386.c gcc/gcc/config/i386/i386.c
*** gcc.orig/gcc/config/i386/i386.c Thu Jul 22 06:42:02 2010
--- gcc/gcc/config/i386/i386.c Thu Aug 19 17:24:05 2010
***************
*** 4842,4847 ****
--- 4842,4855 ----
return false;
}
+ static bool
+ ix86_function_naked (const_tree fntype)
+ {
+ if (lookup_attribute ("naked", DECL_ATTRIBUTES (fntype)))
+ return true;
+ return false;
+ }
+
static enum calling_abi
ix86_function_abi (const_tree fndecl)
{
***************
*** 8478,8483 ****
--- 8486,8494 ----
struct ix86_frame frame;
HOST_WIDE_INT allocate;
int gen_frame_pointer = frame_pointer_needed;
+
+ if (ix86_function_naked (current_function_decl))
+ return ;
ix86_finalize_stack_realign_flags ();
***************
*** 8978,8983 ****
--- 8989,8997 ----
HOST_WIDE_INT offset, red_offset;
struct machine_cfa_state cfa_state_save = *ix86_cfa_state;
bool using_drap;
+
+ if (ix86_function_naked (current_function_decl))
+ return ;
ix86_finalize_stack_realign_flags ();
***************
*** 26117,26122 ****
--- 26131,26152 ----
return NULL_TREE;
}
+ static tree
+ ix86_handle_naked_attribute (tree *node, tree name,
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+ {
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute only applies to functions",
+ name);
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ return NULL_TREE;
+ }
+
static bool
ix86_ms_bitfield_layout_p (const_tree record_type)
{
***************
*** 28988,28993 ****
--- 29018,29024 ----
{ "sysv_abi", 0, 0, false, true, true, ix86_handle_abi_attribute },
{ "ms_hook_prologue", 0, 0, true, false, false, ix86_handle_fndecl_attribute },
/* End element. */
+ { "naked", 0, 0, true, false, false, ix86_handle_naked_attribute },
{ NULL, 0, 0, false, false, false, NULL }
};
diff -cr gcc.orig/gcc/function.c gcc/gcc/function.c
*** gcc.orig/gcc/function.c Fri Feb 26 15:58:57 2010
--- gcc/gcc/function.c Thu Aug 19 17:11:26 2010
***************
*** 5212,5224 ****
start_sequence ();
epilogue_end = emit_note (NOTE_INSN_EPILOGUE_BEG);
seq = gen_epilogue ();
! emit_jump_insn (seq);
!
! /* Retain a map of the epilogue insns. */
! record_insns (seq, NULL, &epilogue_insn_hash);
! set_insn_locators (seq, epilogue_locator);
! seq = get_insns ();
end_sequence ();
insert_insn_on_edge (seq, e);
--- 5212,5228 ----
start_sequence ();
epilogue_end = emit_note (NOTE_INSN_EPILOGUE_BEG);
seq = gen_epilogue ();
!
! if (seq)
! {
! emit_jump_insn (seq);
! /* Retain a map of the epilogue insns. */
! record_insns (seq, NULL, &epilogue_insn_hash);
! set_insn_locators (seq, epilogue_locator);
! }
!
! seq = get_insns ();
end_sequence ();
insert_insn_on_edge (seq, e);