Подтвердить что ты не робот

Как создать 4KB Linux файлы, которые отображают 3D-сцену?

Я только что узнал о конкурсе 4k demo scene. Он состоит в создании исполняемого файла размером 4 КБ, который создает приятную 3D-сцену. Процитированная демонстрация была создана для Windows, поэтому мне было интересно, как можно создать 4KB сцены OpenGL в Linux.

Голый "мир привет" уже потребляет 8 КБ:

$ cat ex.c
#include <stdio.h>

int main()
{
       printf("Hello world\n");
}
$ gcc -Os ex.c -o ex
$ ls -l ex
-rwxrwxr-x 1 cklein cklein 8374 2012-05-11 13:56 ex
4b9b3361

Ответ 1

Основная причина, по которой при стандартных настройках вы не можете сделать небольшой инструмент, так это то, что в ваш двоичный файл вставляется множество символов и ссылок на стандартные библиотеки. Вы должны быть явным, чтобы удалить даже этот базовый материал.

Вот как я это сделал:

http://phresnel.org/gpl/4k/ntropy2k7/

Релевантные параметры:

В основном самоочевидность:

gcc main.c -o fourk0001 -Os -mfpmath=387 \
  -mfancy-math-387 -fmerge-all-constants -fsingle-precision-constant \
  -fno-math-errno -Wall -ldl -ffast-math -nostartfiles -nostdlib  \
  -fno-unroll-loops -fshort-double

Массаж:

strip помогает избавиться от ненужных символов, встроенных в ваш двоичный файл:

strip -R .note -R .comment -R .eh_frame -R .eh_frame_hdr -s fourk0001

код:

Вам, возможно, придется тщательно продумать и проб и ошибок. Иногда петля дает меньший код, иногда вызов, иногда сильную встроенную функцию. В моем коде, например, вместо наличия чистого связанного списка, который содержит все преобразования пламени в фантастическом полиморфном стиле, у меня есть фиксированный массив, где каждый элемент представляет собой большой объект, содержащий все параметры, используемые или неиспользуемые, в качестве объединения всех пламен как на бумаге пламени Скотта Дрейвса.

Ваши трюки не будут переносимыми, другие версии g++ могут давать субоптимальные результаты.

Обратите внимание, что с указанными выше параметрами вы не записываете функцию main(), а скорее функцию _start().

Также обратите внимание, что использование библиотек немного отличается. Вместо того, чтобы связывать SDL и стандартные библиотечные функции классным, удобным способом, вы должны сделать это вручную. Например.

void *libSDL = dlopen( "libSDL.so", RTLD_LAZY );
void *libC = dlopen( "libc.so", RTLD_LAZY );
#if 1
    SDL_SetVideoMode_t sym_SDL_SetVideoMode = dlsym(libSDL, "SDL_SetVideoMode");
    g_sdlbuff = sym_SDL_SetVideoMode(WIDTH,HEIGHT,32,SDL_HWSURFACE|SDL_DOUBLEBUF);
#else
    ((SDL_SetVideoMode_t)dlsym(libSDL, "SDL_SetVideoMode"))(WIDTH,HEIGHT,32,SDL_HWSURFACE|SDL_DOUBLEBUF);
#endif


//> need malloc, probably kinda craft (we only use it once :| )
//> load some sdl cruft (cruft!)
malloc_t sym_malloc = dlsym( libC, "malloc" );
sym_rand   = dlsym( libC, "rand" );
sym_srand  = dlsym( libC, "srand" );
sym_SDL_Flip          = dlsym(libSDL, "SDL_Flip");
sym_SDL_LockSurface   = dlsym(libSDL, "SDL_LockSurface");
sym_SDL_UnlockSurface = dlsym(libSDL, "SDL_UnlockSurface");
sym_SDL_MapRGB        = dlsym(libSDL, "SDL_MapRGB");

И хотя никакой ассемблер не должен быть поврежден, ваш код может дать UB.


изменить:

Ой, я лгал о сборке.

void _start() {
    ...
    asm( "int $0x80" :: "a"(1), "b"(42) );
}

это приведет к возврату вашей программы 42.

Ответ 2

Учебное пособие по созданию виртуозных программ для создания реальных программ ELF Executables для Linux - это интересная статья, которая проходит поэтапный процесс создания ELF исполняемый как можно меньше.

Я не хочу испортить финал, но автор получает его намного меньше, чем 4K;)