Estoy usando glad en un archivo que se compila como una biblioteca de objetos compartidos. Cuando
Cargo dinámicamente una función de esa biblioteca y la llamo, obtengo un segfault.
Este error de segmentación ocurre solo cuando la función cargada dinámicamente contiene llamadas a
Funciones OpenGL que han sido cargadas por glad. Si uso Glew, en lugar de contento,
en la biblioteca, el programa funciona como se esperaba.
He intentado hacer un ejemplo razonablemente mínimo que reproduzca el problema.
Se abre una ventana proporcionada por glfw, una función se carga dinámicamente desde
lib.so
con dlopen()
y dlsym()
, y se llama a esa función. los
La función simplemente borra la pantalla a azul.
Cuando se usa glad, se lanza un segfault durante la llamada a glClearColor()
.
$ chmod +x build.sh && ./build.sh && ./main
build.sh
$ .build.sh && ./main
.
├── build.sh
├── include
│ ├── glad
│ │ └── glad.h
│ └── KHR
│ └── khrplatform.h
└── src
├── glad.c
├── lib.c
└── main.c
4 directories, 6 files
#/usr/bin/sh
gcc -std=c99 -Iinclude -Wall -Wextra -Wshadow \
src/main.c src/glad.c -o main \
-ldl -lglfw -lGL
gcc -std=c99 -Iinclude -Wall -Wextra -Wshadow -fpic -shared \
src/lib.c src/glad.c -o lib.so \
-ldl -lglfw -lGL
# building the library with GLEW fixes the problem
#gcc -std=c99 -Wall -Wextra -Wshadow -fpic -shared \
# -DUSE_GLEW \
# src/lib.c -o lib.so \
# -ldl -lglfw -lGL -lGLEW
/*
OpenGL loader generated by glad 0.1.24a0 on Thu May 31 07:06:52 2018.
Language/Generator: C/C++
Specification: gl
APIs: gl=3.3
Profile: compatibility
Extensions:
Loader: True
Local files: False
Omit khrplatform: False
Commandline:
--profile="compatibility" --api="gl=3.3" --generator="c" --spec="gl" --extensions=""
Online:
http://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D3.3
*/
// ...
#ifdef USE_GLEW
#include <GL/glew.h>
#else
#include <glad/glad.h>
#endif
void draw_blue_screen()
{
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
#include <stdio.h>
#include <stddef.h>
#include <dlfcn.h>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
typedef void (draw_blue_screen_func)(void);
int main(void)
{
if (!glfwInit())
{
fprintf(stderr, "GLFW initialization failed\n");
return -1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
GLFWwindow* window = glfwCreateWindow(800, 600, "example", NULL, NULL);
if (!window)
{
fprintf(stderr, "GLFW window creation failed\n");
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress))
{
fprintf(stderr, "glad initialization failed\n");
glfwDestroyWindow(window);
glfwTerminate();
return -1;
}
// Dynamically load a function from lib.so
void *lib_code = dlopen("./lib.so", RTLD_LAZY);
draw_blue_screen_func *draw_blue_screen = (draw_blue_screen_func *) dlsym(lib_code, "draw_blue_screen");
uint64_t frame_number = 0;
while (!glfwWindowShouldClose(window))
{
printf("Frame %" PRIu64 "\n", frame_number);
draw_blue_screen();
glfwSwapBuffers(window);
glfwPollEvents();
frame_number++;
}
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
Además, ¡gracias por alegrarte! Ha sido bastante agradable de usar.
Oye,
finalmente tuve tiempo de investigar esto. El problema aquí es que lib tampoco funciona con glew, parece funcionar porque se vincula con libGL
y glew usa los símbolos de libGL.so
, compare:
/tmp/issue151 » ldd lib.so # built with USE_GLEW
linux-vdso.so.1 (0x00007fff6434d000)
libdl.so.2 => /lib/libdl.so.2 (0x00007f3a8a97e000)
libGLEW.so.2.1 => /lib/libGLEW.so.2.1 (0x00007f3a8a6d6000)
libc.so.6 => /lib/libc.so.6 (0x00007f3a8a31a000)
/usr/lib64/ld-linux-x86-64.so.2 (0x00007f3a8ad84000)
libGL.so.1 => /lib/libGL.so.1 (0x00007f3a8a08f000)
libX11.so.6 => /lib/libX11.so.6 (0x00007f3a89d50000)
libGLX.so.0 => /lib/libGLX.so.0 (0x00007f3a89b1f000)
libXext.so.6 => /lib/libXext.so.6 (0x00007f3a8990d000)
libGLdispatch.so.0 => /lib/libGLdispatch.so.0 (0x00007f3a89657000)
libpthread.so.0 => /lib/libpthread.so.0 (0x00007f3a89439000)
libxcb.so.1 => /lib/libxcb.so.1 (0x00007f3a89210000)
libXau.so.6 => /lib/libXau.so.6 (0x00007f3a8900c000)
libXdmcp.so.6 => /lib/libXdmcp.so.6 (0x00007f3a88e06000)
y
/tmp/issue151 » ldd lib.so # built without USE_GLEW (glad)
linux-vdso.so.1 (0x00007ffeab9c2000)
libdl.so.2 => /lib/libdl.so.2 (0x00007efc18716000)
libc.so.6 => /lib/libc.so.6 (0x00007efc1835a000)
/usr/lib64/ld-linux-x86-64.so.2 (0x00007efc18b36000)
Agregué algunos printf adicionales en sus archivos fuente:
printf("[lib] glClearColor: %p@%p\n", glClearColor, &glClearColor);
printf("[lib] glClear: %p@%p\n", glClear, &glClear);
printf("[lib] glFramebufferTexture: %p@%p\n", glFramebufferTexture, &glFramebufferTexture);
#ifdef USE_GLEW
printf("[glew] glClearColor: %p@%p\n", __glewClearColorx, &__glewClearColorx);
#endif
[glad] glClearColor: 0x7fb491c2d720<strong i="17">@0x55de31f07428</strong>
[glad] glClear: 0x7fb491c2d600<strong i="18">@0x55de31f06af0</strong>
[dlsym] glClearColor: 0x7fb4939fb720<strong i="19">@0x7fff96d92858</strong>
[dlsym] glClear: 0x7fb4939fb600<strong i="20">@0x7fff96d92850</strong>
Frame 0
[lib] glClearColor: 0x7fb4939fb720<strong i="21">@0x7fb4939fb720</strong>
[lib] glClear: 0x7fb4939fb600<strong i="22">@0x7fb4939fb600</strong>
[lib] glFramebufferTexture: (nil)<strong i="23">@0x7fb48db18050</strong>
[glew] glClearColor: (nil)<strong i="24">@0x7fb48db13db8</strong>
Como puede ver, glFramebufferTexture
es nil
así como el símbolo de glew interno para glClearColor
. lib.c
se rompería en el momento en que use cualquier cosa que no sea OpenGL 1.0.
Puede solucionar esto inicializando OpenGL (glad o glew) en su biblioteca:
void lib_init()
{
#ifndef USE_GLEW
gladLoadGL();
#endif
}
// Dynamically load a function from lib.so
void *lib_code = dlopen("./lib.so", RTLD_LAZY);
draw_blue_screen_func *draw_blue_screen = (draw_blue_screen_func *) dlsym(lib_code, "draw_blue_screen");
((void(*)()) dlsym(lib_code, "lib_init"))();
No sé si puede hacer algunos trucos y obligar a la biblioteca a usar los símbolos ya cargados de su aplicación, puede funcionar si se vincula dinámicamente contra glad / glew como una biblioteca dinámica en ambos archivos ( main.c
y lib.c
) pero, sinceramente, no estoy lo suficientemente familiarizado con POSIX ni con los enlaces dinámicos.
Espero haber respondido a tu pregunta.
Gracias por echarle un vistazo a esto. Después de ver una solución funcional a mi ejemplo, terminé investigando y aprendiendo mucho más sobre lo que está haciendo glad cuando llamo gladLoadGL()
. Ahora tiene sentido por qué los símbolos no eran accesibles para la biblioteca de objetos compartidos.
Comentario más útil
Además, ¡gracias por alegrarte! Ha sido bastante agradable de usar.