_the_answer:
subl $12, %esp
movl $42, %eax
addl $12, %esp
ret
El primer subl disminuye el puntero de la pila, para dejar espacio a las variables que pueden usarse en su función. Se puede usar una ranura para el puntero de marco, otra para sostener la dirección de retorno, por ejemplo. Dijiste que debería omitir el puntero del marco. Eso generalmente significa que omite cargas/tiendas para guardar/restaurar el puntero del marco. Pero a menudo el código aún reservará memoria para ello. La razón es que hace que el código que analiza la pila sea mucho más fácil. Es fácil dar al desplazamiento de la pila un ancho mínimo y así usted sabe que siempre puede acceder a FP + 0x12, para llegar al primer espacio variable local, incluso si omite guardar el puntero del marco.
Bueno, eax
en x86 se utiliza para manejar el valor de retorno de la persona que llama, hasta donde yo sé. Y el último complemento simplemente destruye el marco creado previamente para su función.
El código que genera las instrucciones al inicio y al final de las funciones se denomina "epílogo" y "prólogo" de la función. Esto es lo que hace mi puerto cuando se tiene que crear el prólogo de una función en GCC (que es mucho más compleja para los puertos del mundo real que tienen la intención de ser lo más rápido y más versátil posible):
void eco32_prologue(void) {
int i, j;
/* reserve space for all callee saved registers, and 2 additional ones:
* for the frame pointer and return address */
int regs_saved = registers_to_be_saved() + 2;
int stackptr_off = (regs_saved * 4 + get_frame_size());
/* decrement the stack pointer */
emit_move_insn(stack_pointer_rtx,
gen_rtx_MINUS(SImode, stack_pointer_rtx,
GEN_INT(stackptr_off)));
/* save return adress, if we need to */
if(eco32_ra_ever_killed()) {
/* note: reg 31 is return address register */
emit_move_insn(gen_rtx_MEM(SImode,
plus_constant(stack_pointer_rtx,
-4 + stackptr_off)),
gen_rtx_REG(SImode, 31));
}
/* save the frame pointer, if it is needed */
if(frame_pointer_needed) {
emit_move_insn(gen_rtx_MEM(SImode,
plus_constant(stack_pointer_rtx,
-8 + stackptr_off)),
hard_frame_pointer_rtx);
}
/* save callee save registers */
for(i=0, j=3; i<FIRST_PSEUDO_REGISTER; i++) {
/* if we ever use the register, and if it's not used in calls
* (would be saved already) and it's not a special register */
if(df_regs_ever_live_p(i) &&
!call_used_regs[i] && !fixed_regs[i]) {
emit_move_insn(gen_rtx_MEM(SImode,
plus_constant(stack_pointer_rtx,
-4 * j + stackptr_off)),
gen_rtx_REG(SImode, i));
j++;
}
}
/* set the new frame pointer, if it is needed now */
if(frame_pointer_needed) {
emit_move_insn(hard_frame_pointer_rtx,
plus_constant(stack_pointer_rtx, stackptr_off));
}
}
omití algunos código que trata con otros problemas, principalmente con decirle a GCC cuáles son las instrucciones importantes para el manejo de excepciones (es decir, dónde se almacena el puntero del marco, etc.). Bueno, los registros guardados en línea son los que la persona que llama no necesita guardar antes de una llamada. La función llamada se preocupa por guardar/restaurarlos según sea necesario. Como puede ver en las primeras líneas, siempre asignamos espacio para la dirección de retorno y el puntero del marco. Ese espacio es solo unos pocos bytes y no importará. Pero solo generamos las tiendas/cargas cuando sea necesario. Finalmente, tenga en cuenta que el puntero de marco "duro" es el registro de puntero de marco "real". Es necesario debido a algunas razones internas de gcc. El indicador "frame_pointer_needed" es establecido por GCC, siempre que pueda no omitiendo el almacenamiento del puntero de marco. En algunos casos, debe almacenarse, por ejemplo, cuando se usa alloca
(cambia el stackpointer de forma dinámica). GCC se preocupa por todo eso.Tenga en cuenta que ha pasado un tiempo desde que escribí ese código, así que espero que los comentarios adicionales que agregué arriba no sean todos incorrectos :)
4.0.1 (Apple Inc. compilación 5488). Supongo que es un error. –
@Mike, no es un error. El código funciona bien ya que el addl invierte el subl. Es ineficiente, pero definitivamente no es un error. – paxdiablo
Puede que no sea un error, podría ser que 4.3 sea más inteligente al descubrir qué instrucciones son seguras para eliminar. – flussence