[Editar] Esta no es la respuesta correcta, ya que la respuesta de Fritz es claramente lo que se buscaba :) Pero dejaré que esta respuesta permanezca aquí para la discusión de las convenciones de llamadas. Especialmente las funciones variadic (aquellas con un número variable de argumentos) son interesantes a este respecto.
Esto se suma a la respuesta de JvO, que sugiere obtener el puntero de pila obteniendo la dirección de una variable asignada de pila. También he usado esta técnica. Pero Olin observó que la variable podría no asignarse desde la pila, lo que también es cierto. Esto me llevó a pensar en el siguiente enfoque:
void *GetStack(int *i, ...) {
return &i;
}
La variable que pasa los argumentos garantiza que el primer parámetro debe colocarse en una dirección RAM, ya que el resto de los argumentos tienen la garantía de seguirlo en la memoria (el primer argumento debe ser pasable a una macro va_start), y como tal hay una buena probabilidad de que esté en la pila. Entonces, si bien no identifica la dirección exacta de la parte superior de la pila, podría estar bastante cerca y debería valer la pena intentarlo si el método de JvO no funciona.
PS. Si sabe que el primer argumento debe o no debe ser un puntero, continúe y edite la respuesta.
[Editar] Acabo de darme cuenta de que la pregunta era específica para 8051, así que hice una prueba rápida en el compilador SDCC. SDCC utiliza una asignación de árbol de llamadas para superponer las variables locales en direcciones estáticas de forma predeterminada y el código
void * GetStack() {
int i;
return &i;
}
compila en
_GetStack:
mov dptr,#_GetStack_i_1_1
mov b,#0x00
ret
Esto significa que i no está en la pila, es una dirección estática decidida por el compilador. Creo que es tan dependiente del compilador y del modelo de memoria que asm es la única manera real de hacerlo.
Mi primera función sugerida
void *GetStack2(int *i, ...) {
return &i;
}
parece mejorar un poco, se compila en:
GetStack2:
push _bp
mov _bp,sp
mov a,_bp
add a,#0xfb
mov r2,a
mov r3,#0x00
mov r4,#0x0
mov dpl,r2
mov dph,r3
mov b,r4
mov sp,_bp
pop _bp
ret
que al menos hace referencia a SP. Con asm, el código podría ser mucho más limpio, supongo.