Search code examples
clinuxopengllinkerdemoscene

Linking an SDL/openGL application manually using ld


I'm trying to create a minimal sized executable for a demoscene contest. I'm trying to minimize the size of the executable by linking it myself.

Here is my minimal main.c, taken from http://www.int21.de/linux4k/ It draws a white triangle on the screen:

#include "SDL/SDL.h"
#include "GL/gl.h"

void _start(){
    SDL_Event event;

    SDL_SetVideoMode(640,480,0,SDL_OPENGL|SDL_FULLSCREEN);

    SDL_ShowCursor(SDL_DISABLE);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-1.33,1.33,-1,1,1.5,100);
    glMatrixMode(GL_MODELVIEW);
    glEnable(GL_DEPTH_TEST);
    glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);

    glLoadIdentity();
    glBegin(GL_TRIANGLES);
    glVertex3i(1,1,-10);
    glVertex3i(1,-1,-10);
    glVertex3i(-1,1,-10);
    glEnd();
    SDL_GL_SwapBuffers();

    do{
        SDL_PollEvent(&event);
    } while (event.type!=SDL_KEYDOWN);
    SDL_Quit();
}

I am using void _start() instead of int main(), because I don't want to use the C runtime. Here are my build commands (my machine is running Ubuntu Linux):

gcc -c main.c
ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc -lSDL -lGL main.o -o main

The program crashes on SDL_SetVideoMode. gdb reports:

Program received signal SIGSEGV, Segmentation fault.
_dl_map_object_from_fd (name=0x7ffff77dfcec "libXrender.so.1", fd=-1, fbp=0x7fffffffd908, 
    realname=0x601de0 "/usr/lib/x86_64-linux-gnu/libXrender.so.1", loader=<optimized out>, l_type=<optimized out>, 
    mode=-1879048190, stack_endp=0x7fffffffdc68, nsid=0) at dl-load.c:1574

What is wrong? If I change void _start() to int main(), and compile the whole thing with gcc main.c -o main -lSDL -lGL, it works just fine. This working version and the self-linked broken version have exactly the same list of linked libraries when I inspect the executables with ldd.


Solution

  • TL;DR: Patient: "Doctor, it hurts when I do ${THAT}" – Doctor: "Then don't do ${THAT}".

    If you don't want to have the C runtime in there you must make sure that you don't use any code that relies on the C runtime being available and more importantly being initialized. SDL strongly depends on the facilities of libc (which is why you probably added that -lc so that SDL can be properly linked), so when you link it, you need all that libc stuff. However for libc to properly work it must be initialized, which is what _start() does.

    If you want to get your executable size down, which yes also involved getting rid of the (bloated GNU) libc, you'll have to do a lot of things yourself and/or patch libraries you use not to rely on the things you want to remove.