Al compilar bibliotecas compartidas en gcc, la opción -fPIC compila el código como independiente de la posición. ¿Hay alguna razón (rendimiento o no) por la cual no compilaría todas las posiciones de códigos independientes?¿Por qué no todo el código compilado es independiente de la posición?
Respuesta
Se añade una indirección. Con el código de posición independiente, debes cargar la dirección de tu función y luego saltar a ella. Normalmente, la dirección de la función ya está presente en la secuencia de instrucciones.
Elegido por simplicidad. – ojblass
Sí, hay motivos de rendimiento. Algunos accesos están efectivamente bajo otra capa de indirección para obtener la posición absoluta en la memoria.
También está el GOT (tabla de compensación global) que almacena compensaciones de variables globales. Para mí, esto parece una tabla de corrección de IAT, que está clasificada como dependiente de la posición por wikipedia y algunas otras fuentes.
Estoy votando pero seleccionando el otro por pura simplidumbre. – ojblass
Además, el hardware de memoria virtual en la mayoría de los procesadores modernos (utilizado por la mayoría de los SO modernos) significa que gran cantidad de código (todas las aplicaciones de espacio de usuario, salvo el uso peculiar de mmap o similar) no necesitan ser independientes de posición. Cada programa obtiene su propio espacio de direcciones que piensa que comienza en cero.
Además de la respuesta aceptada. Una cosa que perjudica mucho el rendimiento del código PIC es la falta de "direccionamiento relativo de IP" en x86. Con el "direccionamiento relativo de IP", puede solicitar datos que sean X bytes del puntero de instrucción actual. Esto haría que el código PIC sea mucho más simple.
Los saltos y las llamadas, por lo general son EIP relativos, por lo que realmente no suponen un problema. Sin embargo, acceder a los datos requerirá un pequeño truco extra. A veces, un registro se reservará temporalmente como un "puntero base" a los datos que el código requiere. Por ejemplo, una técnica común es abusar de la forma en que funcionan las llamadas en x86:
call label_1
.dd 0xdeadbeef
.dd 0xfeedf00d
.dd 0x11223344
label_1:
pop ebp ; now ebp holds the address of the first dataword
; this works because the call pushes the **next**
; instructions address
; real code follows
mov eax, [ebp + 4] ; for example i'm accessing the '0xfeedf00d' in a PIC way
Ésta y otras técnicas de añadir una capa de direccionamiento indirecto a los datos de accesos. Por ejemplo, el GOT (tabla de compensación global) utilizado por los compiladores gcc.
x86-64 agregó un modo "RIP relative" que hace que las cosas sean lot simpler.
IIRC MIPS no tiene direcciones relativas a PC, excepto saltos relativos –
Porque la implementación de código completamente independiente de posición agrega una restricción al generador de código que puede evitar el uso de operaciones más rápidas, o agrega pasos adicionales para preservar esa restricción.
Esto podría ser una compensación aceptable para obtener multiprocesamiento sin un sistema de memoria virtual, donde confíe en que los procesos no invaden la memoria de los demás y pueden necesitar cargar una aplicación en particular en cualquier dirección base.
En muchos sistemas modernos las compensaciones de rendimiento son diferentes, y un cargador de reubicación a menudo es menos costoso (cuesta cualquier código de tiempo que se cargue primero) que lo mejor que un optimizador puede hacer si tiene dominio libre. Además, la disponibilidad de espacios de direcciones virtuales oculta la mayor parte de la motivación para la independencia de posición en primer lugar.
This article explica cómo funciona PIC y lo compara con la alternativa - load time relocation. Creo que es relevante para tu pregunta.
publicación relevante! = Respuesta – Nick
@Nick: No estoy de acuerdo. Si ayuda al asker, es una respuesta. Señalar un artículo relevante o dos puede proporcionar una gran cantidad de información. –
No hay conclusión en esta publicación, solo un enlace a un artículo. Ni siquiera una pista de que el PIC no se utiliza de forma predeterminada debido a problemas de rendimiento. – Nick
position-independent code
tiene una sobrecarga de rendimiento en la mayoría de la arquitectura, ya que requiere un registro adicional.
Por lo tanto, esto es para fines de rendimiento.
En la actualidad, el sistema operativo y el compilador establecen por defecto todo el código como código de posición independiente. Intenta compilar sin el distintivo -fPIC, el código se compilará bien, pero recibirás una advertencia. Las ventanas similares a OS usan una técnica llamada asignación de memoria para lograr esto.
- 1. PIC (código independiente de posición)
- 2. Código independiente de posición y tabla variable
- 3. Rendimiento del código compilado por el compilador compilado
- 4. ¿Por qué la JVM no es independiente de la plataforma, dado que Java (el idioma) es independiente de la plataforma?
- 5. ¿Por qué el código JIT consume tanta memoria que el código compilado o interpretado?
- 6. ¿Por qué es necesario compilar el código Java pero el código JavaScript no?
- 7. ¿Por qué el programa C++ compilado para la plataforma x64 es más lento que el compilado para x86?
- 8. Código de posición independiente, bibliotecas compartidas y carillas de código: hacer que funcionen juntas
- 9. ¿Por qué el Diccionario de C# no implementa todo IDictionary?
- 10. ¿Por qué la altura y el atributo superior no funcionan cuando la posición es relativa?
- 11. Diferencia en código independiente de la posición: 86 vs x86-64
- 12. código compilado impar
- 13. ¿Por qué todo en WPF es borroso?
- 14. ¿Por qué el código de C# compilado sobre la marcha no funciona cuando se conecta un depurador?
- 15. -fPIE ("ejecutable independiente de la posición) opción (gcc, ld)
- 16. Descargar el ensamblado compilado por CodeDom
- 17. ¿Incluye Java comentarios sobre el código compilado?
- 18. ¿Por qué una llamada de función vacía en Python es un 15% más lenta para el código python compilado dinámicamente?
- 19. El código ScriptManager.RegisterStartupScript no funciona, ¿por qué?
- 20. ¿Por qué el código de Moose es tan lento?
- 21. cómo marcar el código de Java tal que no es compilado
- 22. ¿Es posible depurar código compilado en tiempo de ejecución?
- 23. ¿Por qué assert simplemente termina un programa compilado para iPhone?
- 24. ¿Todo el código de Groovy es válido con Groovy ++?
- 25. ¿Puede Java ejecutar un código scala compilado?
- 26. ¿Por qué este código no es seguro para subprocesos?
- 27. ¿Puedo llamar a la función de tiempo de ejecución de CUDA desde el código de C++ no compilado por nvcc?
- 28. ¿Por qué 'Código no es lo suficientemente genérico'?
- 29. ¿Por qué mi código es tan lento?
- 30. ¿Es R un lenguaje compilado?
Pero wowest no es del todo correcto. Muchas llamadas de función y saltos usan saltos relativos, por lo que ni siquiera necesitan una tabla de salto después de moverse. – Unknown
mirando el código ensamblador generado parece que la dirección de la función se carga cuando aparece un código que no es fpico, es simplemente un salto. ¿Estoy malinterpretando tu declaración? – ojblass
@ojblass lo que quiero decir es que algunos saltos son como "saltar 50 instrucciones antes que aquí" o "saltar 5 instrucciones hacia atrás" en lugar de "saltar a 0x400000". Por lo tanto, decir que tiene que cargar una dirección cada vez con -fPIC no es del todo cierto. – Unknown