¿C tiene un ABI estándar?

De una discusión en otro lugar :

C ++ no tiene ABI estándar

Pero tampoco C, ¿verdad?

En cualquier plataforma dada, prácticamente lo hace. No sería útil como lingua franca para la comunicación entre idiomas si faltara.

¿Cuál es su opinión sobre esto?

C no define ABI. De hecho, hace todo lo posible para evitar definir un ABI. Esas personas, que como yo, que han dedicado la mayor parte de su progtwigción a progtwigr en C en architectures de 16/32/64 bits con bytes de 8 bits, aritmética de complemento a 2 y espacios de direcciones planos, estarán bastante sorprendidos al leer el intrincado lenguaje de el estándar actual de C.

Por ejemplo, lea las cosas sobre los punteros. El estándar no dice nada tan simple como “un puntero es una dirección” porque eso supondría una suposición sobre el ABI. En particular, permite que los punteros estén en espacios de direcciones diferentes y tengan un ancho variable.

Un ABI es un mapeo desde el modelo de ejecución del lenguaje a una combinación particular máquina / sistema operativo / comstackdor. No tiene sentido definir uno en la especificación del lenguaje porque corre el riesgo de excluir implementaciones C en algunas architectures.

C no tiene ABI estándar en principio, pero en la práctica, esto rara vez importa: usted hace lo que hace su vendedor de sistema operativo.

Tome las convenciones de llamadas en x86 Windows, por ejemplo: La API de Windows usa la llamada convención de llamadas ‘estándar’ (stdcall). Por lo tanto, cualquier comstackdor que quiera interactuar con el sistema operativo necesita implementarlo. Sin embargo, stdcall no es compatible con todas las características del lenguaje C90 (por ejemplo, funciones de llamada sin prototipos, funciones variadas). Como Microsoft proporcionó un comstackdor de C, se necesitaba una segunda convención de llamadas, llamada convención de llamadas ‘C’ (cdecl). La mayoría de los comstackdores de C en Windows usan esto como su convención de llamadas predeterminada, y por lo tanto son interoperables.

En principio, lo mismo podría haber sucedido con C ++, pero como el C ++ ABI (incluida la convención de llamadas) es necesariamente mucho más elaborado, los proveedores de comstackdores no acordaron un solo ABI, pero aún podían interoperar cayendo de nuevo a la extern "C" .

Un ABI, incluso para C, tiene partes que son bastante independientes de la plataforma, partes que dependen del procesador (qué registros deben guardarse, que se usan para pasar parámetros, …) y partes que dependen del SO (más o menos) los mismos factores que para el procesador, ya que la architecture no impone algunas elecciones, sino que son el resultado de compensaciones, además de que algunos SO tienen una noción de excepción independiente del lenguaje, por lo que un comstackdor para cualquier lenguaje debe generar lo correcto para manejar aquellos, el manejo de los hilos también puede imponer cosas en el ABI: si un registro apunta a TLS, no puede usarlo para lo que desee).

En teoría, cada comstackdor puede tener su propio ABI. Pero generalmente, para un par de procesadores / SO, el ABI es reparado por el proveedor del sistema operativo, que a menudo también proporciona un comstackdor de C y bibliotecas comunes que usan ese ABI y los competidores prefieren ser compatibles. (No me sorprendería que existan excepciones para algunos sistemas operativos para los cuales C no es un lenguaje de progtwigción importante).

Pero el proveedor del sistema operativo puede cambiar de ABI por una u otra razón (las nuevas versiones de procesadores pueden tener características que desee usar en el ABI para una; por ejemplo, algunos han pedido un ABI de 32 bits para x86_64 que permita usar todos los registros) . Durante la fase de migración, que puede durar mucho tiempo, es posible que deba manejar dos ABI.

El ABI para C es específico de la plataforma: cubre cuestiones tales como la asignación de registros y las convenciones de llamadas, que obviamente son específicas de un procesador en particular. Aquí hay unos ejemplos:

  • El ARM ABI (incluye C ++)
  • El ABI embebido PowerPC
  • Los varios ABI de x86

x86 ha tenido muchas convenciones de llamadas, que son extensiones en Windows para declarar cuál se utiliza. Los ABI de plataforma para Linux incorporado también han cambiado con el tiempo, lo que lleva a un espacio de usuario incompatible. Vea un poco del historial del puerto ARM Linux aquí , que muestra los problemas en la transición a un ABI más nuevo.

tampoco C, ¿verdad?
Derecha

En cualquier plataforma dada, prácticamente lo hace. No sería útil como lingua franca para la comunicación entre idiomas si faltara.
Más o menos podría referirse a los valores predeterminados específicos de la architecture elegidos por los proveedores de comstackdores de C que se adaptan a otros idiomas. Entonces, si el comstackdor ARM C de Keil usará de izquierda a derecha pequeños parámetros endian y astackr para pasar argumentos y algún registro predeterminado para el valor de retorno, entonces la “C” externa de otros comstackdores asumirá la compatibilidad con dicho esquema.

Si bien tal acuerdo puede considerarse parte de ABI, a diferencia del contexto de ejecución administrada, como el entorno de prueba del navegador JVM, esto está lejos de ser un estándar completo de ABI por sí mismo.

Aunque se han realizado varios bashs para definir un único ABI para una architecture determinada a través de múltiples sistemas operativos (particularmente para i386 en sistemas Unix), los esfuerzos no han tenido tanto éxito. En cambio, los sistemas operativos tienden a definir sus propios ABI …

Citando … Progtwigción del sistema Linux página 4.

C no tiene un ABI estándar. Esto se ilustra fácilmente con todas las convenciones de llamadas (cdecl, fastcall y stdcall) que se usan allí. Cada uno es un ABI diferente.

Antes del estándar C89, los comstackdores de C para muchas plataformas usaban esencialmente el mismo ABI, excepto las variaciones en el tamaño de los datos. Para las máquinas cuya stack crece hacia abajo, el código que llama a una función empujará los argumentos en la stack en orden de derecha a izquierda y luego llamará a la función (empujando la dirección de retorno en el proceso). Una función llamada dejaría sus argumentos en la stack, y la persona que realiza la llamada ajustaría el puntero de stack para eliminarlos [o, en algunas architectures, podría ajustar los valores astackdos en su lugar]. Si bien hizo innecesario que la mayoría de los progtwigs se basen en esa convención, se mantuvo en uso durante muchos años porque era simple y funcionaba bastante bien. Si bien no existía un documento “oficial” que estableciera que como un “estándar” multiplataforma, la mayoría de los comstackdores que apuntaban a máquinas con stacks de crecimiento descendente funcionaron de esa manera, lo que condujo a un mayor nivel de coherencia de lo que existe actualmente.