Pregunta

¿Hay alguna manera de conocer y generar el tamaño de pila que necesita una función en el momento de la compilación en C?Esto es lo que me gustaría saber:

Tomemos alguna función:

void foo(int a) {
    char c[5];
    char * s;
    //do something
    return;
}

Al compilar esta función, me gustaría saber cuánto espacio de pila consumirá cuando se llame.Esto podría resultar útil para detectar la declaración en la pila de una estructura que oculta un búfer grande.

Estoy buscando algo que imprima algo como esto:

archivo foo.c:El uso de la función foo stack es n bytes

¿Hay alguna manera de no mirar el ensamblaje generado para saber eso?¿O un límite que se puede establecer para el compilador?

Actualizar :No estoy tratando de evitar el desbordamiento de la pila en tiempo de ejecución para un proceso determinado, estoy buscando una manera de encontrar antes del tiempo de ejecución, si el uso de la pila de funciones, según lo determinado por el compilador, está disponible como salida del proceso de compilación.

Digámoslo de otra manera:¿Es posible saber el tamaño de todos los objetos locales de una función?Supongo que la optimización del compilador no será mi amiga, porque alguna variable desaparecerá pero un límite superior está bien.

¿Fue útil?

Solución

El código del kernel de Linux se ejecuta en una pila de 4K en x86.Por eso les importa.Lo que usan para verificar eso es un script en Perl que escribieron, que puede encontrar como scripts/checkstack.pl en un tarball del kernel reciente (2.6.25 lo tiene).Se ejecuta en la salida de objdump, la documentación de uso se encuentra en el comentario inicial.

Creo que ya lo usé para binarios de espacio de usuario hace mucho tiempo, y si sabes un poco de programación en Perl, es fácil arreglarlo si no funciona.

De todos modos, lo que básicamente hace es mirar automáticamente la salida de GCC.Y el hecho de que los piratas informáticos del kernel hayan escrito una herramienta de este tipo significa que no existe una forma estática de hacerlo con GCC (o tal vez se agregó hace muy poco, pero lo dudo).

Por cierto, con objdump del proyecto mingw y ActivePerl, o con Cygwin, deberías poder hacerlo también en Windows y también en binarios obtenidos con otros compiladores.

Otros consejos

StackAnlyser parece examinar el código ejecutable en sí más información de depuración.Lo que se describe por esta respuesta, es lo que estoy buscando, el analizador de pila me parece excesivo.

Algo similar a lo que existe para ADA estaría bien.Mire esta página del manual del mosquito:

22.2 Análisis de uso de pila estática

Una unidad compilada con -fstack-usage generará un archivo adicional que especifica la cantidad máxima de pila utilizada, por función.El archivo tiene el mismo nombre base que el archivo del objeto de destino con una extensión .su.Cada línea de este archivo se compone de tres campos:

* The name of the function.
* A number of bytes.
* One or more qualifiers: static, dynamic, bounded. 

El segundo campo corresponde al tamaño de la parte conocida del marco de función.

El calificador estático significa que el tamaño del marco de la función es puramente estático.Generalmente significa que todas las variables locales tienen un tamaño estático.En este caso, el segundo campo es una medida confiable de la utilización de la pila de funciones.

El calificador dinámico significa que el tamaño del marco de la función no es estático.Ocurre principalmente cuando algunas variables locales tienen un tamaño dinámico.Cuando este calificador aparece solo, el segundo campo no es una medida confiable del análisis de la pila de funciones.Cuando está calificado con límites, significa que el segundo campo es un máximo confiable de utilización de la pila de funciones.

No veo por qué un análisis de código estático no podría dar una cifra suficientemente buena para esto.

Es trivial encontrar todas las variables locales en cualquier función determinada, y el tamaño de cada variable se puede encontrar mediante el estándar C (para tipos integrados) o calculándolo (para tipos complejos como estructuras y uniones).

Claro, no se puede garantizar que la respuesta sea 100% precisa, ya que el compilador puede realizar varios tipos de optimizaciones como relleno, colocar variables en registros o eliminar por completo variables innecesarias.Pero cualquier respuesta que dé debería ser al menos una buena estimación.

Hice una búsqueda rápida en Google y encontré Analizador de pila pero supongo que otras herramientas de análisis de código estático tienen capacidades similares.

Si desea una cifra 100% precisa, entonces tendrá que mirar el resultado del compilador o verificarlo durante el tiempo de ejecución (como sugirió Ralph en su respuesta)

Sólo el compilador lo sabría realmente, ya que es la persona que junta todas tus cosas.Tendría que mirar el ensamblaje generado y ver cuánto espacio está reservado en el preámbulo, pero eso realmente no tiene en cuenta cosas como alloca que hacen lo suyo en tiempo de ejecución.

Suponiendo que esté en una plataforma integrada, es posible que su cadena de herramientas pueda intentarlo.Los buenos compiladores integrados comerciales (como, por ejemplo, el compilador Arm/Keil) a menudo producen informes del uso de la pila.

Por supuesto, las interrupciones y la recursividad suelen estar un poco fuera de alcance, pero te da una idea aproximada si alguien ha cometido algún error terrible con un buffer de varios megabytes en la pila en alguna parte.

No es exactamente "tiempo de compilación", pero haría esto como un paso posterior a la compilación:

  • deje que el vinculador cree un archivo de mapa para usted
  • para cada función en el archivo de mapa, lea la parte correspondiente del ejecutable y analice el prólogo de la función.

Esto es similar a lo que hace StackAnalyzer, pero mucho más simple.Creo que analizar el ejecutable o el desensamblado es la forma más fácil de llegar al resultado del compilador.Si bien el compilador sabe esas cosas internamente, me temo que no podrá obtenerlas (puede pedirle al proveedor del compilador que implemente la funcionalidad, o si usa un compilador de código abierto, puede hacerlo usted mismo o dejar que alguien lo haga). para ti).

Para implementar esto es necesario:

  • ser capaz de analizar el archivo de mapa
  • entender el formato del ejecutable
  • saber cómo puede ser el prólogo de una función y poder "decodificarlo"

Lo fácil o difícil que sería esto depende de su plataforma de destino.(¿Incorporado?¿Qué arquitectura de CPU?¿Qué compilador?)

Todo esto definitivamente se puede hacer en x86/Win32, pero si nunca hiciste algo como esto y tienes que crear todo esto desde cero, pueden pasar algunos días antes de que termines y tengas algo funcionando.

No en general.El problema de la detención en la informática teórica sugiere que ni siquiera se puede predecir si un programa general se detiene ante una entrada determinada.Calcular la pila utilizada para la ejecución de un programa en general sería aún más complicado.Entonces:No.Quizás en casos especiales.

Digamos que tiene una función recursiva cuyo nivel de recursividad depende de la entrada que puede ser de longitud arbitraria y ya no tiene suerte.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top