├── Clutter └── src │ ├── Makefile │ ├── build.sh │ ├── clutter.c │ └── unpack_lzma.header ├── README.md ├── SDL └── src │ ├── Makefile │ ├── build.sh │ ├── sdl.c │ └── unpack_lzma.header ├── SDL2 └── src │ ├── Makefile │ ├── build.sh │ ├── sdl2.c │ └── unpack_lzma.header ├── file └── src │ ├── Makefile │ ├── build.sh │ ├── file.c │ └── unpack_lzma.header ├── framebuffer └── src │ ├── Makefile │ ├── build.sh │ ├── fb.c │ └── unpack_lzma.header ├── framebuffer_asm ├── Makefile ├── fb.asm └── unpack_lzma.header ├── framebuffer_custom_elf └── src │ ├── Makefile │ ├── build.sh │ ├── elf32.s │ ├── elf64.s │ ├── fb.c │ ├── script_32.ld │ ├── script_64.ld │ └── unpack_lzma.header ├── framebuffer_custom_elf_overlap └── src │ ├── Makefile │ ├── build.sh │ ├── elf32.s │ ├── elf64.s │ ├── fb.c │ ├── script_32.ld │ ├── script_64.ld │ └── unpack_lzma.header ├── framebuffer_custom_elf_overlap_asminit32 └── src │ ├── Makefile │ ├── build.sh │ ├── elf32.s │ ├── fb.c │ └── script_32.ld └── framebuffer_custom_elf_overlap_pwrite64 └── src ├── Makefile ├── build.sh ├── elf32.s ├── fb.c └── script_32.ld /Clutter/src/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | STANDARD_FLAGS=-std=c99 -pedantic -Wno-switch -Wno-conversion -Wno-uninitialized -Wno-strict-aliasing \ 3 | -fno-exceptions -ffast-math -fsingle-precision-constant -fno-ident \ 4 | -funsafe-math-optimizations -fvisibility=hidden -fmerge-all-constants \ 5 | -fno-align-functions -fno-align-loops -fno-math-errno #-march=native 6 | OPTI_FLAGS=-Os -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-stack-protector -ftree-vectorize -fopt-info-vec-optimized \ 7 | -fomit-frame-pointer -fno-math-errno -fdata-sections -ffunction-sections -fno-stack-protector -fno-stack-check \ 8 | -nostartfiles -nodefaultlibs -no-pie -fno-plt -fno-pic -fno-unroll-loops -Winline 9 | LINKER_FLAGS=-Wl,--gc-sections \ 10 | -Wl,--build-id=none -z norelro -Wl,-z,noseparate-code -Wl,--no-eh-frame-hdr \ 11 | -Wl,--no-ld-generated-unwind-info -Wl,--hash-style=sysv \ 12 | -Wl,-z,nodynamic-undefined-weak -Wl,--strip-all 13 | NAME=clutter 14 | # https://github.com/BR903/ELFkickers 15 | SSTRIP=~/ELFkickers/sstrip/sstrip 16 | LZMA_ARGS=--format=lzma -9 --extreme --lzma1=preset=9,lc=0,lp=0,pb=0,nice=32,depth=9,dict=16384 --keep 17 | 18 | all: 19 | $(CC) -o $(NAME) $(NAME).c -DWIDTH=$(WIDTH) -DHEIGHT=$(HEIGHT) $(STANDARD_FLAGS) $(OPTI_FLAGS) `pkg-config clutter-1.0 --cflags --libs` $(LINKER_FLAGS) 20 | strip -R .note -R .data -R .bss -R .comment -R .eh_frame -R .eh_frame_hdr -R .note.gnu.build-id -R .got -R .got.plt -R .gnu.version -R .rela.dyn -R .shstrtab -R .gnu.hash $(NAME) 21 | $(SSTRIP) -z $(NAME) 22 | # clear useless bits (taken from blackle Tiny X11 Trans Flag) 23 | sed -i 's/_edata/\x00\x00\x00\x00\x00\x00/g' $(NAME); 24 | sed -i 's/__bss_start/\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00/g' $(NAME); 25 | sed -i 's/_end/\x00\x00\x00\x00/g' $(NAME); 26 | # 27 | wc -c $(NAME) 28 | # compress & stub 29 | lzma $(LZMA_ARGS) $(NAME) 30 | cat unpack_lzma.header $(NAME).lzma > $(NAME) 31 | chmod +x $(NAME) 32 | rm $(NAME).lzma 33 | # remove CRC32 (4 bytes) 34 | truncate -s -4 $(NAME) 35 | # truncate some more bytes (NOTE : may works but unsafe) 36 | #truncate -s -1 $(NAME) 37 | wc -c $(NAME) 38 | mv $(NAME) ../$(NAME)_$(WIDTH)x$(HEIGHT)x32 39 | -------------------------------------------------------------------------------- /Clutter/src/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | make WIDTH="800" HEIGHT="600" 3 | -------------------------------------------------------------------------------- /Clutter/src/clutter.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void _start() { 4 | #ifdef __x86_64 5 | // 64 bits fix due to XauReadAuth (libxau.so) segfault when compiled with SSE4 / AVX2 6 | __asm__("sub $8, %rsp\n"); 7 | #endif 8 | 9 | clutter_init(0, 0); 10 | 11 | ClutterActor *stage = clutter_stage_new(); 12 | ClutterEffect *shader = clutter_shader_effect_new(CLUTTER_FRAGMENT_SHADER); 13 | 14 | clutter_shader_effect_set_shader_source((ClutterShaderEffect *)shader, "void main(){gl_FragColor=vec4(1.,0.,0.,1.);}"); 15 | clutter_actor_add_effect(stage, shader); 16 | 17 | clutter_actor_show(stage); 18 | 19 | clutter_main(); 20 | } 21 | -------------------------------------------------------------------------------- /Clutter/src/unpack_lzma.header: -------------------------------------------------------------------------------- 1 | HOME=/tmp/g;sed 1d $0|lzcat>~;chmod +x ~;~ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Collection of tiny C ELF programs with graphics output 2 | ===== 3 | 4 | This repository is a collection of small ELF (Executable and Linkable Format) executables able to output graphics. All compiled with **GCC 7.5.0**. 5 | 6 | The goal was to build a collection of very small standalone Linux graphics programs written in C with minimal amount of assembly (which is inline and mainly used for [syscall](https://en.wikipedia.org/wiki/System_call)) 7 | 8 | The rules was to be able to output & view graphics data, it also should be able to quit properly using Ctrl+C (SIGINT) 9 | 10 | All of them compile down to less than 512 bytes, some are less than 256 bytes and two (32 bits only) less than 128 bytes (80 bytes !) 11 | 12 | There is only one 100% assembly framebuffer program to show how all of this compete against 'compliant' ELF [credits](https://www.muppetlabs.com/~breadbox/software/tiny/return42.html) 13 | 14 | It borrow several tricks from several sources mainly coming from the [Demoscene](https://en.wikipedia.org/wiki/Demoscene) 15 | 16 | All 100% C programs work in either 64 bits or 32 bits (must append `-m32` to GCC flags), 32 bits vs 64 bits binary size depends on the method but 32 bits is generally smaller. 17 | 18 | This was used for [my procedural graphics 128b/256b intro](https://www.pouet.net/groups.php?which=15005) although some are 100% assembly. 19 | 20 | The best method for anything real-time is probably the "Framebuffer with custom ELF headers", the binary size is the same as the assembly version, it also allow full controls over the ELF header and ASM parts. 21 | 22 | A good and up to date source for sizecoding on Linux (also show how to output sounds and more): [http://www.sizecoding.org/wiki/Linux](http://www.sizecoding.org/wiki/Linux) 23 | 24 | ## Why 25 | 26 | Fun, portability, readability, accessibility. 27 | 28 | It is mainly targeted at [sizecoding](http://www.sizecoding.org/wiki/Main_Page) stuff. (art of creating very tiny programs) 29 | 30 | * Portability : There is some inline assembly but it is still way more portable than an assembly program. 31 | * Readability : Not always true but generally it is, when doing sizecoding the code can get pretty weird / cryptic, with C it is more straightforward. 32 | * Accessibility : Allow to get into sizecoding quickly with common programming language. 33 | 34 | As a major downside there is less controls over the generated code and maybe some odd behaviors due to compiler bugs etc. 35 | 36 | ## Build 37 | 38 | Just go into any directory then into `src` directory and type `sh build.sh` this will invoke `make` multiple times for all defined width / height parameters in `build.sh` then all generated executables will go into the upper directory. 39 | 40 | This was built with **GCC 7.5.0** 41 | 42 | **NOTE : If you get crashes try to build the program a second time; due to unsolved issues in the build process when switching target.** 43 | 44 | ## How 45 | 46 | applicable to all except C + custom ELF header and ASM version : 47 | 48 | * using GCC compiler optimizations through compiler flags (see Makefile of each programs) 49 | * `-nostartfiles -nodefaultlibs` linker options among others (don't link to libc / don't use default startup code) 50 | * usage of [strip](https://en.wikipedia.org/wiki/Strip_(Unix)) to remove various useless stuff from the executable binary (symbols, debug data etc.) 51 | * usage of [sstrip](https://www.muppetlabs.com/~breadbox/software/elfkickers.html) to remove even more useless stuff that strip doesn't (section headers) 52 | * clean more useless bits from the executable with a sed pass [from blackle](https://github.com/blackle/Tiny-X11-Trans-Flag) 53 | * compress the ELF binary with LZMA (Note: this step + next step of course rely on some tools like **lzcat** **sed** which must be available on the OS; this is generally not an issue as they are available by default on most Linux OS) 54 | * build a binary from a small shell script + the compressed binary, the shell script unpack and run itself, it unpack the executable to `/tmp/g`, make it executable and may perform additional stuff (such as outputting audio, clearing the terminal, exiting properly etc.) 55 | * truncate some bytes left from the compression format (CRC32 checksum) 56 | 57 | Some details / credits about the optimizations can be gathered [here](https://in4k.github.io/wiki/linux) 58 | 59 | If the compression / shell script may feel like cheating one can still compile some programs (framebuffer, file) down to less than 256 bytes (even 128 bytes) for file / fbdev output. 60 | 61 | There is still some room to remove some bytes by not clearing the terminal output or not exiting properly. (~11 bytes to most) 62 | 63 | There is also the `-march=` GCC option which can have varying result on binary size. 64 | 65 | When compression is used changing some constants can sometimes lead to some gain. (depends on executable content) 66 | 67 | `strace` is usefull on optimized binary to see any problems with the syscall 68 | 69 | There is also a framebuffer version with GCC output + custom ELF headers merged together to form a small binary, it is probably the best of all methods here. 70 | 71 | ## Graphics output 72 | 73 | Several methods are used to output graphics, of which : 74 | 75 | * [Portable Pixmap](https://en.wikipedia.org/wiki/Netpbm#File_formats) file output 76 | * fbdev; framebuffer (eg. `/dev/fb0`), open + mmap OR open + pwrite64 using the stack as buffer (best for realtime / feedback effects) 77 | * SDL 78 | * SDL2 79 | 80 | GPU-only method using a GLSL fragment shader : 81 | * [clutter](https://blogs.gnome.org/clutter/) 82 | 83 | Framebuffer / file output is probably the most compatible option followed by SDL as i believe it is installed by default on many systems. 84 | 85 | ## Sound output 86 | 87 | There is no sound output on the provided examples but it can be added easily by using `aplay` in the shell script (and piping data to it such as obviously `/dev/random`) 88 | 89 | Here is some [code](http://www.sizecoding.org/wiki/Linux) 90 | 91 | ### File output 92 | 93 | Only limited to static graphics data. 94 | 95 | This output a `.ppm` (Portable Pixmap) image named `i` with a centered white pixel in current directory and call `xdg-open` to open it. 96 | 97 | There is two versions of the program in `file.c` : 98 | 99 | * standard version with open / write syscall, it is slightly larger than the one below 100 | * (default) shortcut version which write the binary data to stdout (single write syscall) which is then redirected by the shell script to the `.ppm` file 101 | 102 | 64 bits ELF result : 103 | 104 | * 190 bytes optimized + compressed 105 | 106 | Note : 107 | 108 | * Due to PPM format some more bytes may be taken when the image resolution is increased. 109 | * Some more bytes could be gained by calling `eog` or `feh` instead of `xdg-open` but it would probably reduce compatibility. 110 | * The image should be named `.ppm` to be compatible with most files explorer. 111 | 112 | ### Framebuffer 113 | 114 | This use the framebuffer device `/dev/fb0` (fbdev) to output graphics data. (white centered pixel) 115 | 116 | The framebuffer device sometimes require that the user must either be in `video` or `tty` group otherwise the executable must be run by `root` or with `sudo` 117 | 118 | The generated binary res / bit depth should match the framebuffer settings in order to work.` 119 | 120 | 64 bits ELF result : 121 | 122 | * 240 bytes optimized 123 | * 182 bytes optimized + compressed 124 | 125 | Note : 126 | 127 | * 176 bytes by removing null syscall parameters, this is probably safe on x86-64 but i don't know if it is safe for x86 platforms so i left that out. 128 | * for static graphics (procedural) some bytes can be gained by using a static buffer + call to single write syscall + adjusting the shell script to output to /dev/fb0 just like the "file output" example 129 | 130 | ### Framebuffer with custom 32 / 64 bits ELF headers 131 | 132 | Same as before with a custom 32 / 64 bits assembly ELF header, probably the best of all methods due to flexibility and size of generated binary. Can be adapted for file output easily. 133 | 134 | The main advantage over all methods here is : C code + hand made ELF header customizations / complete controls 135 | 136 | The main disadvantage is : it can be harder to use since some sections like .rodata are left out so for example any float constants in C code don't work as-is, they must be defined somewhere in the assembly code and referenced in C code through pointers (see sources) **if you only use integers** in your program it should work as-is so [fixed-point arithmetic](https://en.wikipedia.org/wiki/Fixed-point_arithmetic) should perhaps be prefered over floats. 137 | 138 | Another (small) disadvantage is less portability, you may have to rewrite the header for each platforms. 139 | 140 | How ? The program is compiled with GCC (with optimization flags), a binary blob (without headers) is then extracted and included inside a custom ELF header assembled with NASM, the result is then compressed. 141 | 142 | There is some unsafe shortcuts (perhaps) compared to the other methods such as : 143 | 144 | * ELF padding / ABI target / version field is used to store the framebuffer device (/dev/fb0) string 145 | * Syscall null arguments are discarded (see `fb.c` comments), this rely on the asumption that all registers are set to 0 when the program start. 146 | 147 | 32 bits ELF result (1920x1080) : 148 | 149 | * 165 bytes optimized 150 | * 196 bytes optimized + compressed (why ?) 151 | 152 | 64 bits ELF result (1920x1080) : 153 | 154 | * 171 bytes optimized 155 | * 164 bytes optimized + compressed (153 bytes if the console isn't cleared / program doesn't exit properly) 156 | 157 | Original idea / implementation came from [this article](http://mainisusuallyafunction.blogspot.com/2015/01/151-byte-static-linux-binary-in-rust.html) 158 | 159 | Note : Non compressed version does not quit properly 160 | 161 | Note : See `build.sh` to target 32 or 64 bits platform (run it twice if you switch because there is some unsolved issues in how variables are handled in the makefile) 162 | 163 | Note : The resulting 64 bits binary can be disassembled with `objdump -b binary -D -m i386:x86-64 binary_name` 164 | 165 | ### Framebuffer with custom ELF headers + fields overlap 166 | 167 | Same as before except some ELF header fields are overlapped (31 bytes gain for 64 bits version) 168 | 169 | Note : This does not respect the ELF specification so potentially unsafe. 170 | 171 | Note : 32 bits version goes further than just overlapping headers by integrating bits of [Whirlwind Tutorial](http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html) it is also maybe more unsafe than 64 bits due to some shortcuts (e_sh* values are actual code + fb0 string null byte on e_ehsize) 172 | 173 | 32 bits ELF result (1920x1080) : 174 | 175 | * **127 bytes** optimized 176 | * 180 bytes optimized + compressed 177 | 178 | 64 bits ELF result (1920x1080) : 179 | 180 | * 140 bytes optimized 181 | * 159 bytes optimized + compressed (148 bytes if the console isn't cleared / program doesn't exit properly) 182 | 183 | Compression does not seem to help anymore so it is disabled by default. 184 | 185 | Note : Some potentially unsafe tricks can be used to gain ~4 bytes for the 32 bits ELF by tweaking the `sys_mmap` function (no push / pop + single movl and one arg) bringing the 32 bits ELF to around **123 bytes** 186 | 187 | Some more bytes can be gained for the 32 bits version by hand coding some stuff in assembly (see next) but at this point it is probably better to go for pure assembly. :) 188 | 189 | ### Framebuffer with custom ELF headers + fields overlap + x86 framebuffer init (open / mmap) 190 | 191 | Same as before except the framebuffer initialization (fopen / mmap calls) is hand coded; 32 bits x86 only 192 | 193 | open/mmap disadvantage : reading from the mmaped memory is very slow, can also get tearing and may be hard to do feedback effects, see the pwrite64 below for fixes 194 | 195 | 32 bits ELF result (1920x1080) : 196 | 197 | * **80 bytes** 198 | 199 | It use optimized framebuffer initialization code from [lintro](https://www.pouet.net/prod.php?which=58560) a 128 bytes intro by frag/fsqrt 200 | 201 | This is probably one of the tiniest a C fbdev program can be although there is still some tricks to gain ~3 bytes such as changing entry point (see [lintro sources](https://www.pouet.net/prod.php?which=58560)) 202 | 203 | Ideal for 128 bytes intro although at this point it is probably better to ditch C and do pure assembly :) 204 | 205 | ### Framebuffer with custom ELF headers + fields overlap + x86 framebuffer init (open / pwrite64 + stack usage) 206 | 207 | Same as before except the framebuffer initialization (fopen / pwrite64 calls) is hand coded and some room is made on the stack for the buffer; 32 bits x86 only 208 | 209 | open/pwrite64/stack advantage : fast read, no tearings, allow feedback effects, quite easy to do scrolling and glitchy effects by using the pwrite64 parameters 210 | 211 | open/pwrite64/stack disadvantage : sligthly larger, use the stack as a buffer so if your C program use the stack some data may go into the display buffer, it may crash if you write data that the C program use (can be mitigated with some offset) 212 | 213 | Another disadvantage of using the stack is that the stack size is sometimes limited to 8Mb, it is probably safe to hold a 1920x1080 32 bits framebuffer but maybe not more. 214 | 215 | note : the pwrite64 is hand coded in the C program because it is easy to embed it into a loop that way (youll have to call it each time you want to draw) 216 | 217 | Once again it is probably better to ditch C and do pure assembly at this point :) 218 | 219 | 32 bits ELF result (1920x1080) : 220 | 221 | * **87 bytes** 222 | 223 | Idea based on [http://www.sizecoding.org/wiki/Linux](http://www.sizecoding.org/wiki/Linux) there is some more tricks on there! 224 | 225 | ### SDL 226 | 227 | This use the SDL library to output graphics data. (white centered pixel) 228 | 229 | Only two calls : `SDL_SetVideoMode` and `SDL_Flip`, `SDL_Init` call seem uneeded so it was left out. 230 | 231 | Exiting properly was a bit tough through SDL calls so it was handled in the shell script by running the program in background, setting up a SIGINT trap which then kill the process. 232 | 233 | 64 bits ELF result : 234 | 235 | * 969 bytes optimized 236 | * 404 bytes optimized + compressed 237 | 238 | Switching to 32 bits ELF actually free some more bytes : 239 | 240 | 32 bits ELF result : 241 | 242 | * 374 bytes 243 | 244 | ### SDL2 245 | 246 | This use the SDL2 library to output graphics data. (white centered pixel) 247 | 248 | Unless the SDL version this one doesn't seem to require any additional setup to exit properly ? 249 | 250 | 64 bits ELF result : 251 | 252 | * 1073 bytes optimized 253 | * 456 bytes optimized + compressed 254 | 255 | ### Clutter (accelerated) 256 | 257 | This use the Clutter libary to output graphics data through a GLSL fragment shader. (a window filled with red) 258 | 259 | The Clutter package should be installed in popular distributions, if not the package to install on Ubuntu is : `sudo apt install libclutter-1.0-dev` 260 | 261 | 64 bits ELF result : 262 | 263 | * 1417 bytes optimized 264 | * 503 bytes optimized + compressed 265 | 266 | Probably the best choice for "modern" graphics as it is accelerated. There is probably not enough room for anything complex in 512 bytes (at least on 64 bits) because Clutter GLSL symbols are long named. 267 | 268 | Didn't try the 32 bits version but this probably save some more bytes. 269 | 270 | A good source of fragment shaders to learn from is [Shadertoy](https://www.shadertoy.com) 271 | 272 | ### Framebuffer + pure assembly 273 | 274 | 64 bits assembly program that use the framebuffer device `/dev/fb0` (fbdev) to output graphics data. (white centered pixel) 275 | 276 | This respect the ELF specification; better gains (~36 bytes) can be achieved by overlapping ELF headers or switching to 32 bits. See [tiny ELF](http://www.muppetlabs.com/~breadbox/software/tiny/return42.html) 277 | 278 | 64 bits ELF result : 279 | 280 | * 196 bytes 281 | * 169 bytes compressed 282 | 283 | This is only ~13 bytes less than the C version! (and ~7 bytes if syscall null values are discarded in the C program) 284 | 285 | Note : this is the same size as the Framebuffer custom ELF, there is some small size differences due to the added loop. 286 | 287 | Conclusion : For 128b / 256b programs GCC can do a sufficient job but it highly depend on the code, GCC may use the stack heavily which is sometimes not good for sizecoding, it will not beat hand optimized assembly which may at least have 25% less bytes. 288 | 289 | ### More tricks 290 | 291 | Some more bytes can be gained by tweaking the ELF header (see overlap example), this can be highly tricky / unsafe. Some more can be gained with compiler options such as `-fomit-frame-pointer` `-march=`; depend on code. 292 | 293 | GCC option `-ffixed-reg` where 'reg' is a register name can be used to tell GCC to avoid generating code with this register, this may be useful in some cases. 294 | 295 | Also highly recommend to disassemble and analyze the resulting binary `objdump -b binary -D -m i386 ../fb_1920x1080x32`, GCC may put some useless setup bits (for stack alignment etc.) in there just before entering main like some useless `push` (once had 7 bytes gain by looking at that!). 296 | 297 | GCC version can also influence the binary size, Clutter sample for instance has some bytes difference between GCC 7, 8 and 12. On GCC-12 the `-Oz` option is available and may help to get some more bytes. -------------------------------------------------------------------------------- /SDL/src/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | STANDARD_FLAGS=-std=c99 -pedantic -Wno-switch -Wno-conversion -Wno-uninitialized -Wno-strict-aliasing \ 3 | -fno-exceptions -ffast-math -fsingle-precision-constant -fno-ident \ 4 | -funsafe-math-optimizations -fvisibility=hidden -fmerge-all-constants \ 5 | -fno-align-functions -fno-align-loops -fno-math-errno #-march=native 6 | OPTI_FLAGS=-Os -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-stack-protector -ftree-vectorize -fopt-info-vec-optimized \ 7 | -fomit-frame-pointer -fno-math-errno -fdata-sections -ffunction-sections -fno-stack-protector -fno-stack-check \ 8 | -nostartfiles -nodefaultlibs -no-pie -fno-plt -fno-pic -fno-unroll-loops -Winline 9 | LINKER_FLAGS=-Wl,--gc-sections \ 10 | -Wl,--build-id=none -z norelro -Wl,-z,noseparate-code -Wl,--no-eh-frame-hdr \ 11 | -Wl,--no-ld-generated-unwind-info -Wl,--hash-style=sysv \ 12 | -Wl,-z,nodynamic-undefined-weak 13 | NAME=sdl 14 | # https://github.com/BR903/ELFkickers 15 | SSTRIP=~/ELFkickers/sstrip/sstrip 16 | LZMA_ARGS=--format=lzma -9 --extreme --lzma1=preset=9,lc=0,lp=0,pb=0,nice=32,depth=9,dict=16384 --keep 17 | 18 | all: 19 | $(CC) -o $(NAME) $(NAME).c -DWIDTH=$(WIDTH) -DHEIGHT=$(HEIGHT) $(STANDARD_FLAGS) $(OPTI_FLAGS) -lSDL $(LINKER_FLAGS) 20 | strip -R .note -R .comment -R .bss -R .data -R .rodata -R .hash -R .eh_frame -R .eh_frame_hdr -R .note.gnu.build-id -R .got -R .got.plt -R .gnu.version -R .rela.dyn -R .shstrtab -R .gnu.hash $(NAME) 21 | $(SSTRIP) -z $(NAME) 22 | # clear useless bits (taken from blackle Tiny X11 Trans Flag) 23 | sed -i 's/_edata/\x00\x00\x00\x00\x00\x00/g' $(NAME); 24 | sed -i 's/__bss_start/\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00/g' $(NAME); 25 | sed -i 's/_end/\x00\x00\x00\x00/g' $(NAME); 26 | # 27 | wc -c $(NAME) 28 | # compress & stub 29 | lzma $(LZMA_ARGS) $(NAME) 30 | cat unpack_lzma.header $(NAME).lzma > $(NAME) 31 | chmod +x $(NAME) 32 | rm $(NAME).lzma 33 | # remove CRC32 (4 bytes) 34 | truncate -s -4 $(NAME) 35 | # truncate some more bytes (NOTE : unsafe, upon any segfaults just comment the next line) 36 | truncate -s -2 $(NAME) 37 | wc -c $(NAME) 38 | mv $(NAME) ../$(NAME)_$(WIDTH)x$(HEIGHT)x32 39 | -------------------------------------------------------------------------------- /SDL/src/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | make WIDTH="800" HEIGHT="600" 3 | -------------------------------------------------------------------------------- /SDL/src/sdl.c: -------------------------------------------------------------------------------- 1 | #include "SDL/SDL.h" 2 | 3 | // defined in build.sh 4 | //#define WIDTH 1920 5 | //#define HEIGHT 1080 6 | 7 | void _start() { 8 | #ifdef __x86_64 9 | // 64 bits fix due to XauReadAuth (libxau.so) segfault when compiled with SSE4 / AVX2 10 | __asm__("sub $8, %rsp\n"); 11 | #endif 12 | 13 | //SDL_Init(SDL_INIT_VIDEO); // probably uneeded for pixels stuff, try to enable it if it crash ! 14 | SDL_Surface *screen = SDL_SetVideoMode(WIDTH, HEIGHT, 32, SDL_SWSURFACE); 15 | 16 | int x = WIDTH / 2; 17 | int y = HEIGHT / 2; 18 | 19 | for (;;) { 20 | // put white pixel 21 | Uint8 *p = (Uint8 *)screen->pixels + 300 * screen->pitch + 400 * 4; 22 | *(Uint32 *)p = 16777215; 23 | 24 | SDL_Flip(screen); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SDL/src/unpack_lzma.header: -------------------------------------------------------------------------------- 1 | HOME=/tmp/g;sed 1d $0|lzcat>~;chmod +x ~;~&P=$!;trap "kill -9 $P" INT;wait $P;exit 2 | -------------------------------------------------------------------------------- /SDL2/src/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | STANDARD_FLAGS=-std=c99 -pedantic -Wno-switch -Wno-conversion -Wno-uninitialized -Wno-strict-aliasing \ 3 | -fno-exceptions -ffast-math -fsingle-precision-constant -fno-ident \ 4 | -funsafe-math-optimizations -fvisibility=hidden -fmerge-all-constants \ 5 | -fno-align-functions -fno-align-loops -fno-math-errno #-march=native 6 | OPTI_FLAGS=-Os -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-stack-protector -ftree-vectorize -fopt-info-vec-optimized \ 7 | -fomit-frame-pointer -fno-math-errno -fdata-sections -ffunction-sections -fno-stack-protector -fno-stack-check \ 8 | -nostartfiles -nodefaultlibs -no-pie -fno-plt -fno-pic -fno-unroll-loops -Winline 9 | LINKER_FLAGS=-Wl,--gc-sections \ 10 | -Wl,--build-id=none -z norelro -Wl,-z,noseparate-code -Wl,--no-eh-frame-hdr \ 11 | -Wl,--no-ld-generated-unwind-info -Wl,--hash-style=sysv \ 12 | -Wl,-z,nodynamic-undefined-weak 13 | NAME=sdl2 14 | # https://github.com/BR903/ELFkickers 15 | SSTRIP=~/ELFkickers/sstrip/sstrip 16 | LZMA_ARGS=--format=lzma -9 --extreme --lzma1=preset=9,lc=0,lp=0,pb=0,nice=32,depth=0,dict=16384 --keep 17 | 18 | all: 19 | $(CC) -o $(NAME) $(NAME).c -DWIDTH=$(WIDTH) -DHEIGHT=$(HEIGHT) $(STANDARD_FLAGS) $(OPTI_FLAGS) -lSDL2 $(LINKER_FLAGS) 20 | strip -R .note -R .comment -R .data -R .rodata -R .bss -R .eh_frame -R .eh_frame_hdr -R .note.gnu.build-id -R .got -R .got.plt -R .gnu.version -R .rela.dyn -R .shstrtab -R .gnu.hash $(NAME) 21 | $(SSTRIP) -z $(NAME) 22 | # clear useless bits (taken from blackle Tiny X11 Trans Flag) 23 | sed -i 's/_edata/\x00\x00\x00\x00\x00\x00/g' $(NAME); 24 | sed -i 's/__bss_start/\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00/g' $(NAME); 25 | sed -i 's/_end/\x00\x00\x00\x00/g' $(NAME); 26 | # 27 | wc -c $(NAME) 28 | # compress & stub 29 | lzma $(LZMA_ARGS) $(NAME) 30 | cat unpack_lzma.header $(NAME).lzma > $(NAME) 31 | chmod +x $(NAME) 32 | rm $(NAME).lzma 33 | # remove CRC32 (4 bytes) 34 | truncate -s -4 $(NAME) 35 | # truncate some more bytes (NOTE : unsafe, upon any segfaults just comment the next line) 36 | truncate -s -1 $(NAME) 37 | wc -c $(NAME) 38 | mv $(NAME) ../$(NAME)_$(WIDTH)x$(HEIGHT)x32 39 | -------------------------------------------------------------------------------- /SDL2/src/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | make WIDTH="800" HEIGHT="600" 3 | -------------------------------------------------------------------------------- /SDL2/src/sdl2.c: -------------------------------------------------------------------------------- 1 | #include "SDL2/SDL.h" 2 | 3 | // defined in build.sh 4 | //#define WIDTH 1920 5 | //#define HEIGHT 1080 6 | 7 | void _start() { 8 | #ifdef __x86_64 9 | // 64 bits fix due to XauReadAuth (libxau.so) segfault when compiled with SSE4 / AVX2 10 | __asm__("sub $8, %rsp\n"); 11 | #endif 12 | 13 | //SDL_Init(SDL_INIT_VIDEO); // probably uneeded for pixels stuff, try to enable it if it crash ! 14 | SDL_Window * window = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WIDTH, HEIGHT, 0); 15 | SDL_Surface * window_surface = SDL_GetWindowSurface(window); 16 | 17 | int x = WIDTH / 2; 18 | int y = HEIGHT / 2; 19 | 20 | for (;;) { 21 | // put white pixel 22 | Uint8 *p = (Uint8 *)window_surface->pixels + 300 * window_surface->pitch + 400 * 4; 23 | *(Uint32 *)p = 16777215; 24 | 25 | SDL_UpdateWindowSurface(window); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /SDL2/src/unpack_lzma.header: -------------------------------------------------------------------------------- 1 | HOME=/tmp/g;sed 1d $0|lzcat>~;chmod +x ~;~&P=$!;trap "kill -9 $P" INT;wait $P;exit 2 | -------------------------------------------------------------------------------- /file/src/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | STANDARD_FLAGS=-std=c99 -pedantic -Wno-switch -Wno-conversion -Wno-uninitialized -Wno-strict-aliasing \ 3 | -fno-exceptions -ffast-math -fsingle-precision-constant -fno-ident \ 4 | -funsafe-math-optimizations -fvisibility=hidden -fmerge-all-constants \ 5 | -fno-align-functions -fno-align-loops -fno-math-errno #-march=native 6 | OPTI_FLAGS=-Os -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-stack-protector -ftree-vectorize -fopt-info-vec-optimized \ 7 | -fomit-frame-pointer -fno-math-errno -fdata-sections -ffunction-sections -fno-stack-protector -fno-stack-check \ 8 | -nostartfiles -nodefaultlibs -fno-plt -fno-unroll-loops -Winline -no-pie -fno-pic 9 | LINKER_FLAGS=-Wl,--gc-sections \ 10 | -Wl,--build-id=none -z norelro -Wl,-z,noseparate-code -Wl,--no-eh-frame-hdr \ 11 | -Wl,--no-ld-generated-unwind-info -Wl,--hash-style=sysv \ 12 | -Wl,-z,nodynamic-undefined-weak 13 | NAME=file 14 | # https://github.com/BR903/ELFkickers 15 | SSTRIP=~/ELFkickers/sstrip/sstrip 16 | LZMA_ARGS=--format=lzma -9 --extreme --lzma1=preset=9,lc=0,lp=0,pb=0,nice=32,depth=0,dict=16384 --keep 17 | 18 | all: 19 | $(CC) -o $(NAME) $(NAME).c -DWIDTH=$(WIDTH) -DHEIGHT=$(HEIGHT) $(STANDARD_FLAGS) $(OPTI_FLAGS) $(LINKER_FLAGS) 20 | strip -R .note -R .comment -R .eh_frame -R .eh_frame_hdr -R .note.gnu.build-id -R .got -R .got.plt -R .gnu.version -R .rela.dyn -R .shstrtab -R .gnu.hash $(NAME) 21 | $(SSTRIP) -z $(NAME) 22 | # clear useless bits (taken from blackle Tiny X11 Trans Flag) 23 | sed -i 's/_edata/\x00\x00\x00\x00\x00\x00/g' $(NAME); 24 | sed -i 's/__bss_start/\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00/g' $(NAME); 25 | sed -i 's/_end/\x00\x00\x00\x00/g' $(NAME); 26 | # 27 | wc -c $(NAME) 28 | # compress & stub 29 | lzma $(LZMA_ARGS) $(NAME) 30 | cat unpack_lzma.header $(NAME).lzma > $(NAME) 31 | chmod +x $(NAME) 32 | rm $(NAME).lzma 33 | # remove CRC32 (4 bytes) 34 | truncate -s -4 $(NAME) 35 | # truncate some more bytes (NOTE : unsafe, upon any segfaults or strange behaviors just comment the next line) 36 | truncate -s -1 $(NAME) 37 | wc -c $(NAME) 38 | mv $(NAME) ../$(NAME)_$(WIDTH)x$(HEIGHT)x32 39 | -------------------------------------------------------------------------------- /file/src/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | make WIDTH="800" HEIGHT="600" 3 | -------------------------------------------------------------------------------- /file/src/file.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #ifdef __x86_64 6 | #include 7 | #else 8 | #include 9 | #endif 10 | 11 | // define a RGB PPM (Portable PixMap) file 12 | #define STRINGIZE(A) #A 13 | 14 | #define _PPM_HEADER(W,H) "P6 "W" "H" 255 " 15 | #define PPM_HEADER(W,H) _PPM_HEADER(STRINGIZE(W),STRINGIZE(H)) 16 | 17 | struct ppm { 18 | char header[sizeof(PPM_HEADER(WIDTH, HEIGHT)) - 1]; 19 | char buffer[WIDTH * HEIGHT * 3]; 20 | } image = { PPM_HEADER(WIDTH, HEIGHT), 0 }; 21 | // 22 | 23 | inline static size_t sys_write(int fd, const void *buf, size_t size) { 24 | size_t r; 25 | #ifdef __x86_64 26 | __asm__ volatile("syscall" 27 | : "=a" (r) 28 | : "0"(__NR_write), "D"(fd), "S"(buf), "d"(size) 29 | : "rcx", "r11", "memory"); 30 | #else 31 | __asm__ volatile("int $0x80" 32 | : "=a" (r) 33 | : "0"(__NR_write), "b"(fd), "c"(buf), "d"(size) 34 | : "memory"); 35 | #endif 36 | return r; 37 | } 38 | 39 | inline static int sys_open(const char *filepath, int flags, int mode) { 40 | long r; 41 | #ifdef __x86_64 42 | __asm__ volatile("syscall" 43 | : "=a"(r) 44 | : "0"(__NR_open), "D"(filepath), "S"(flags), "d"(mode) 45 | : "cc", "rcx", "r11", "memory"); 46 | #else 47 | __asm__ volatile("int $0x80" 48 | : "=a"(r) 49 | : "0"(__NR_open), "b"(filepath), "c"(flags), "d"(mode) 50 | : "cc", "edi", "esi", "memory"); 51 | #endif 52 | return r; 53 | } 54 | 55 | void _start() { 56 | // create a .ppm output file (Note : standard version) 57 | //int fd = sys_open(".ppm", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); 58 | 59 | char *buffer = &image.buffer[0]; 60 | 61 | // plot a white pixel at the center of the image 62 | int x = WIDTH / 2; 63 | int y = HEIGHT / 2; 64 | 65 | unsigned int index = (x + y * WIDTH) * 3; 66 | 67 | buffer[index + 0] = 255; 68 | buffer[index + 1] = 255; 69 | buffer[index + 2] = 255; 70 | // 71 | 72 | // write buffer to the opened file (Note : standard version) 73 | //sys_write(fd, &image, sizeof(struct ppm)); 74 | 75 | // shortcut: write to stdout & let the shell script write the file 76 | sys_write(1, &image, sizeof(struct ppm)); 77 | } 78 | -------------------------------------------------------------------------------- /file/src/unpack_lzma.header: -------------------------------------------------------------------------------- 1 | HOME=/tmp/g;sed 1d $0|lzcat>~;chmod +x ~;~>i;xdg-open i;exit 2 | -------------------------------------------------------------------------------- /framebuffer/src/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | STANDARD_FLAGS=-std=c99 -pedantic -Wno-switch -Wno-conversion -Wno-uninitialized -Wno-strict-aliasing \ 3 | -fno-exceptions -ffast-math -fsingle-precision-constant -fno-ident \ 4 | -funsafe-math-optimizations -fvisibility=hidden -fmerge-all-constants \ 5 | -fno-align-functions -fno-align-loops -fno-math-errno #-march=native 6 | OPTI_FLAGS=-Os -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-stack-protector -ftree-vectorize -fopt-info-vec-optimized \ 7 | -fomit-frame-pointer -fno-math-errno -fdata-sections -ffunction-sections -fno-stack-check \ 8 | -nostartfiles -nodefaultlibs -no-pie -fno-plt -fno-pic -fno-unroll-loops -Winline 9 | LINKER_FLAGS=-Wl,--gc-sections \ 10 | -Wl,--build-id=none -z norelro -Wl,-z,noseparate-code -Wl,--no-eh-frame-hdr \ 11 | -Wl,--no-ld-generated-unwind-info -Wl,--hash-style=sysv \ 12 | -Wl,-z,nodynamic-undefined-weak 13 | NAME=fb 14 | # https://github.com/BR903/ELFkickers 15 | SSTRIP=~/ELFkickers/sstrip/sstrip 16 | LZMA_ARGS=--format=lzma -9 --extreme --lzma1=preset=9,lc=0,lp=0,pb=0,nice=32,depth=0,dict=16384 --keep 17 | 18 | all: 19 | $(CC) -o $(NAME) $(NAME).c -DWIDTH=$(WIDTH) -DHEIGHT=$(HEIGHT) $(STANDARD_FLAGS) $(OPTI_FLAGS) $(LINKER_FLAGS) 20 | strip -R .note -R .comment -R .eh_frame -R .eh_frame_hdr -R .note.gnu.build-id -R .got -R .got.plt -R .gnu.version -R .rela.dyn -R .shstrtab -R .gnu.hash $(NAME) 21 | $(SSTRIP) $(NAME) 22 | wc -c $(NAME) 23 | # compress & stub 24 | lzma $(LZMA_ARGS) $(NAME) 25 | cat unpack_lzma.header $(NAME).lzma > $(NAME) 26 | chmod +x $(NAME) 27 | rm $(NAME).lzma 28 | # remove CRC32 (4 bytes) 29 | truncate -s -4 $(NAME) 30 | # truncate some more bytes (NOTE : unsafe, upon any segfaults just comment the next line) 31 | #truncate -s -1 $(NAME) 32 | wc -c $(NAME) 33 | mv $(NAME) ../$(NAME)_$(WIDTH)x$(HEIGHT)x32 34 | -------------------------------------------------------------------------------- /framebuffer/src/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | make WIDTH="1920" HEIGHT="1080" 3 | make WIDTH="800" HEIGHT="600" 4 | -------------------------------------------------------------------------------- /framebuffer/src/fb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #ifdef __x86_64 4 | #include 5 | #else 6 | #include 7 | #endif 8 | 9 | // framebuffer settings (width / height / components should match actual framebuffer settings) 10 | #define FRAMEBUFFER_COMPONENTS 4 11 | #define FRAMEBUFFER_LENGTH (WIDTH * HEIGHT * FRAMEBUFFER_COMPONENTS) 12 | 13 | inline static int sys_open(const char *filepath, int flags, int mode) { 14 | int r; 15 | #ifdef __x86_64 16 | __asm__ volatile("syscall" 17 | : "=a"(r) 18 | : "0"(__NR_open), "D"(filepath), "S"(flags), "d"(mode) 19 | : "cc", "rcx", "r11", "memory"); 20 | #else 21 | __asm__ volatile("int $0x80" 22 | : "=a"(r) 23 | : "0"(__NR_open), "b"(filepath), "c"(flags), "d"(mode) 24 | : "cc", "edi", "esi", "memory"); 25 | #endif 26 | return r; 27 | } 28 | 29 | inline static unsigned int *sys_mmap(unsigned int *addr, unsigned long length, unsigned long prot, unsigned long flags, unsigned long fd) { 30 | #ifdef __x86_64 31 | register volatile int r10 __asm__ ("r10") = flags; register volatile int r8 __asm__ ("r8") = fd; unsigned int *r; 32 | __asm__ volatile ("syscall" : "=a" (r) : "a" (__NR_mmap), "D" (addr), "S" (length), "d" (prot), "r" (r10), "r" (r8) : "cc", "memory", "r11", "rcx"); 33 | return r; 34 | #else 35 | unsigned int args[2] = { (unsigned int)addr, 0 }; 36 | unsigned int *r; 37 | 38 | __asm__ __volatile__("push %%ebp\n" 39 | "movl 4(%%ebx), %%ebp\n" 40 | "movl 0(%%ebx), %%ebx\n" 41 | "int $0x80\n" 42 | "pop %%ebp\n" 43 | : "=a"(r) 44 | : "a"(__NR_mmap2), "b"(&args), 45 | "c"(length), "d"(prot), "S"(flags), "D"(fd)); 46 | 47 | return r; 48 | #endif 49 | } 50 | 51 | void _start() { 52 | int fbfd = sys_open("/dev/fb0", O_RDWR, 0); 53 | unsigned int *buffer = (unsigned int *)sys_mmap(0, FRAMEBUFFER_LENGTH, PROT_READ|PROT_WRITE, MAP_SHARED, fbfd); 54 | 55 | unsigned int x = WIDTH / 2; 56 | unsigned int y = HEIGHT / 2; 57 | 58 | unsigned int index = x + y * WIDTH; 59 | 60 | buffer[index] = 16777215; // white 61 | } 62 | -------------------------------------------------------------------------------- /framebuffer/src/unpack_lzma.header: -------------------------------------------------------------------------------- 1 | HOME=/tmp/g;sed 1d $0|lzcat>~;chmod +x ~;clear;~;exit 2 | -------------------------------------------------------------------------------- /framebuffer_asm/Makefile: -------------------------------------------------------------------------------- 1 | NAME=fb 2 | LZMA_ARGS=--format=lzma -9 --extreme --lzma1=preset=9,lc=0,lp=0,pb=0,nice=32,depth=9,dict=16384 --keep 3 | GZIP_ARGS=-cnk9 4 | ZIP_ARG=-cnk9 5 | 6 | all: build 7 | lzma $(LZMA_ARGS) $(NAME) 8 | cat unpack_lzma.header $(NAME).lzma > $(NAME) 9 | chmod +x $(NAME) 10 | rm $(NAME).lzma 11 | # remove CRC32 (4 bytes) 12 | truncate -s -4 $(NAME) 13 | wc -c $(NAME) 14 | 15 | build: 16 | nasm -fbin -o $(NAME) $(NAME).asm 17 | chmod +x $(NAME) 18 | wc -c $(NAME) 19 | -------------------------------------------------------------------------------- /framebuffer_asm/fb.asm: -------------------------------------------------------------------------------- 1 | BITS 64 2 | org 0x00400000 ;Program load offset 3 | 4 | ;64-bit ELF header 5 | ehdr: 6 | ;ELF Magic + 2 (64-bit), 1 (LSB), 1 (ELF ver. 1), 0 (ABI ver.) 7 | db 0x7F, "ELF", 2, 1, 1, 0 ;e_ident 8 | 9 | times 8 db 0 ;reserved (zeroes) 10 | 11 | dw 2 ;e_type: Executable file 12 | dw 0x3e ;e_machine: AMD64 13 | dd 1 ;e_version: current version 14 | dq _start ;e_entry: program entry address (0x78) 15 | dq phdr - $$ ;e_phoff program header offset (0x40) 16 | dq 0 ;e_shoff no section headers 17 | dd 0 ;e_flags no flags 18 | dw ehdrsize ;e_ehsize: ELF header size (0x40) 19 | dw phdrsize ;e_phentsize: program header size (0x38) 20 | dw 1 ;e_phnum: one program header 21 | dw 0 ;e_shentsize 22 | dw 0 ;e_shnum 23 | dw 0 ;e_shstrndx 24 | ehdrsize equ $ - ehdr 25 | 26 | ;64-bit ELF program header 27 | phdr: 28 | dd 1 ;p_type: loadable segment 29 | dd 5 ;p_flags read and execute 30 | dq 0 ;p_offset 31 | dq $$ ;p_vaddr: start of the current section 32 | dq $$ ;p_paddr: 33 | dq filesize ;p_filesz 34 | dq filesize ;p_memsz 35 | dq 0x200000 ;p_align: 2^11=200000=11 bit boundaries 36 | 37 | ;program header size 38 | phdrsize equ $ - phdr 39 | 40 | %assign WIDTH 1920 41 | %assign HEIGHT 1080 42 | %assign COMPONENTS 4 43 | %assign BUFFER_LENGTH WIDTH * HEIGHT * COMPONENTS 44 | 45 | _start: 46 | ; open /dev/fb0 47 | mov rax, 0x2 48 | mov rdi, data 49 | mov rsi, 0x2 ; O_RDWR 50 | syscall 51 | 52 | ; mmap 53 | mov r8, rax ; fd 54 | mov rax, 0x9 55 | mov rdi, 0 56 | mov rsi, BUFFER_LENGTH 57 | mov rdx, 3 ; PROT_READ|PROT_WRITE 58 | mov r10, 0x01 ; MAP_SHARED 59 | syscall 60 | 61 | mov rbx, rax ; move returned address 62 | 63 | draw_loop: 64 | mov dword [rbx + ((WIDTH / 2 + HEIGHT / 2 * WIDTH) * COMPONENTS)],16777215 65 | jmp short draw_loop 66 | 67 | section .data 68 | data: 69 | db "/dev/fb0" 70 | datasz equ $ - data 71 | 72 | section .bss 73 | bss: 74 | buffer: 75 | resb BUFFER_LENGTH 76 | bsssz equ $ - bss 77 | 78 | filesize equ $ - $$ 79 | -------------------------------------------------------------------------------- /framebuffer_asm/unpack_lzma.header: -------------------------------------------------------------------------------- 1 | HOME=/tmp/g;sed 1d $0|lzcat>~;chmod +x ~;clear;~;exit 2 | -------------------------------------------------------------------------------- /framebuffer_custom_elf/src/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | STANDARD_FLAGS=-std=c99 -pedantic -Wno-switch -Wno-conversion -Wno-uninitialized -Wno-strict-aliasing \ 3 | -fno-exceptions -ffast-math -fsingle-precision-constant -fno-ident \ 4 | -funsafe-math-optimizations -fvisibility=hidden -fmerge-all-constants \ 5 | -fno-align-functions -fno-align-loops -fno-math-errno #-march=native 6 | OPTI_FLAGS=-Os -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-stack-protector -ftree-vectorize -fopt-info-vec-optimized \ 7 | -fomit-frame-pointer -fno-math-errno -fdata-sections -ffunction-sections -fno-stack-check \ 8 | -nostartfiles -nodefaultlibs -no-pie -fno-plt -fno-pic -fno-unroll-loops -Winline 9 | LINKER_FLAGS=-Wl,--gc-sections \ 10 | -Wl,--build-id=none -z norelro -Wl,-z,noseparate-code -Wl,--no-eh-frame-hdr \ 11 | -Wl,--no-ld-generated-unwind-info -Wl,--hash-style=sysv \ 12 | -Wl,-z,nodynamic-undefined-weak 13 | NAME=fb 14 | LZMA_ARGS=--format=lzma -9 --extreme --lzma1=preset=9,lc=0,lp=0,pb=0,nice=32,depth=0,dict=16384 --keep 15 | 16 | all: 17 | rm -f $(NAME).lzma 18 | rm -f payload 19 | rm -f payload.bin 20 | rm -f nm_output 21 | $(eval LD_BITS=$(shell [ $(BITS) = 32 ] && echo "-m elf_i386" || echo "-m elf_x86_64")) 22 | $(CC) -o $(NAME) $(NAME).c -DWIDTH=$(WIDTH) -DHEIGHT=$(HEIGHT) -m$(BITS) $(STANDARD_FLAGS) $(OPTI_FLAGS) $(LINKER_FLAGS) 23 | # ugly 'fix' from seabios for newer version of ld which will fail when linking one executable to another (see: http://sourceware-org.1504.n7.nabble.com/recent-ld-built-for-x86-64-fails-to-accept-16bit-code-as-input-seabios-build-td641750.html) 24 | # original comment: Change e_type to ET_REL so that it can be used to link. Unlike GNU ld, lld does not allow an ET_EXEC input. 25 | # ld 2.30 does not have the problem but 2.36.1 does 26 | # NOTE : the entry point may change due to that so $(ENTRY) below is completely wrong and it result in a crash on my machine (vs ld 2.30) 27 | # don't know yet how to fix it cleanly except by just defining $(ENTRY) to be the address defined in the ld script (padded)... maybe check if that fix can be avoided ? 28 | #printf '\1' | dd of=$(NAME) conv=notrunc bs=1 seek=16 status=none 29 | # source : http://mainisusuallyafunction.blogspot.com/2015/01/151-byte-static-linux-binary-in-rust.html 30 | # 'smash all the sections together, with no alignment padding, then extract that section as a headerless binary blob' 31 | ld --gc-sections $(LD_BITS) -e _start -T script_$(BITS).ld -o payload $(NAME) 32 | objcopy -j combined -O binary payload payload.bin 33 | # determine the entry point address 34 | nm -f posix payload | grep '^_start ' | awk '{print $$3}' > nm_output 35 | # data offset (hex and uppercase) if any data is defined before the payload in elf64.s or elf32.s an offset must be added corresponding to the size of the data (so it compute the correct entry point) 36 | $(eval OFFSET=0) 37 | # get entry point address from nm_output (uppercase hex), compute offset if any and pad the result 38 | $(eval NM_OUTPUT=$(shell cat nm_output | tr '[a-z]' '[A-Z]')) 39 | $(eval NM_OUTPUT=$(shell perl -e 'print sprintf "%016s\n","$(NM_OUTPUT)"')) 40 | $(eval ENTRY=$(shell echo "obase=16;ibase=16;$(NM_OUTPUT) + $(OFFSET)" | bc)) 41 | $(eval ENTRY=$(shell perl -e 'print sprintf "%016s\n","$(ENTRY)"')) 42 | # build the final binary from the binary and custom ELF header 43 | nasm -f bin -o $(NAME) -D entry=0x$(ENTRY) elf$(BITS).s 44 | wc -c $(NAME) 45 | # comment the following two lines if you want raw ELF file (no stub / shell script / LZMA compression) 46 | lzma $(LZMA_ARGS) $(NAME) 47 | cat unpack_lzma.header $(NAME).lzma > $(NAME) 48 | truncate -s -4 $(NAME) 49 | chmod +x $(NAME) 50 | rm -f $(NAME).lzma 51 | rm -f payload 52 | rm -f payload.bin 53 | wc -c $(NAME) 54 | mv $(NAME) ../$(NAME)_$(WIDTH)x$(HEIGHT)x$(BITS) 55 | chmod +x ../$(NAME)_$(WIDTH)x$(HEIGHT)x$(BITS) 56 | -------------------------------------------------------------------------------- /framebuffer_custom_elf/src/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | make WIDTH="1920" HEIGHT="1080" BITS="64" 3 | make WIDTH="800" HEIGHT="600" BITS="64" 4 | -------------------------------------------------------------------------------- /framebuffer_custom_elf/src/elf32.s: -------------------------------------------------------------------------------- 1 | bits 32 2 | org 0x00400000 3 | 4 | ehdr: 5 | db 0x7f, "ELF" ; magic 6 | db 1, 1, 1 ; 32-bits, little endian, version 1 7 | 8 | ; use unused ELF field to store framebuffer target string 9 | ; this also use the ABI target / version field (may be unsafe ?) 10 | db "/dev/fb0", 0 11 | 12 | dw 2 ; e_type = executable 13 | dw 3 ; e_machine 14 | dd 1 ; e_version 15 | dd entry ; e_entry 16 | dd phdr - $$ ; e_phoff 17 | dd 0 ; e_shoff 18 | dd 0 ; e_flags 19 | dw ehdrsize ; e_ehsize 20 | dw phdrsize ; e_phentsize 21 | dw 1 ; e_phnum 22 | dw 0, 0, 0 ; e_sh* 23 | 24 | ehdrsize equ $ - ehdr 25 | 26 | phdr: 27 | dd 1 ; p_type = loadable program segment 28 | dd 0 ; p_offset 29 | dd $$, $$ ; p_vaddr, p_paddr 30 | dd filesize ; p_filesz 31 | dd filesize ; p_memsz 32 | dd 5 ; p_flags = rwx 33 | dd 0x1000 ; p_align 34 | 35 | phdrsize equ $ - phdr 36 | 37 | ; see float note in the C code 38 | ; dd 0.5 39 | 40 | incbin "payload.bin" 41 | 42 | filesize equ $ - ehdr 43 | 44 | -------------------------------------------------------------------------------- /framebuffer_custom_elf/src/elf64.s: -------------------------------------------------------------------------------- 1 | bits 64 2 | org 0x00400000 3 | 4 | ehdr: 5 | db 0x7f, "ELF" ; magic 6 | db 2, 1, 1 ; 64-bits, little endian, version 1 7 | 8 | ; use unused ELF field to store framebuffer target string 9 | ; this also use the ABI target / version field (may be unsafe ?) 10 | db "/dev/fb0", 0 11 | 12 | dw 2 ; e_type = executable 13 | dw 0x3e ; e_machine = x86-64 14 | dd 1 ; e_version 15 | dq entry ; e_entry 16 | dq phdr - $$ ; e_phoff 17 | dq 0 ; e_shoff 18 | dd 0 ; e_flags 19 | dw ehdrsize ; e_ehsize 20 | dw phdrsize ; e_phentsize 21 | dw 1 ; e_phnum 22 | dw 0, 0, 0 ; e_sh* 23 | 24 | ehdrsize equ $ - ehdr 25 | 26 | phdr: 27 | dd 1 ; p_type = loadable program segment 28 | dd 5 ; p_flags = rwx 29 | dq 0 ; p_offset 30 | dq $$, $$ ; p_vaddr, p_paddr 31 | dq filesize ; p_filesz 32 | dq filesize ; p_memsz 33 | dq 0x1000 ; p_align 34 | 35 | phdrsize equ $ - phdr 36 | 37 | ; any data can also go here and are accessible in the C code through pointers but the 'entry' should be correcty updated (see Makefile) so it must have an offset added corresponding to the size of the data 38 | ; note : if you use float constants in your C code, youll most likely want to load them from here manually through pointers address 39 | ; because float constants are loaded from memory and since we don't use any sections any float constants will vanish from the resulting binary 40 | ; unless they are defined here and referenced via pointers in the C code 41 | 42 | ; dd 0.5 43 | 44 | incbin "payload.bin" 45 | 46 | filesize equ $ - ehdr 47 | 48 | -------------------------------------------------------------------------------- /framebuffer_custom_elf/src/fb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #ifdef __x86_64 4 | #include 5 | #else 6 | #include 7 | #endif 8 | 9 | // framebuffer settings (width / height / components should match actual framebuffer settings) 10 | #define FRAMEBUFFER_COMPONENTS 4 11 | #define FRAMEBUFFER_LENGTH (WIDTH * HEIGHT * FRAMEBUFFER_COMPONENTS) 12 | 13 | // note : mode argument is unused since it is null (potentially unsafe, depend if register is initialized to 0 when program run) 14 | inline static int sys_open(char *filepath, int flags, int mode) { 15 | int r; 16 | #ifdef __x86_64 17 | __asm__ volatile("syscall" 18 | : "=a"(r) 19 | : "0"(__NR_open), "D"(filepath), "S"(flags)//, "d"(mode) 20 | : "cc", "rcx", "r11", "memory"); 21 | #else 22 | __asm__ volatile("int $0x80" 23 | : "=a"(r) 24 | : "0"(__NR_open), "b"(filepath), "c"(flags)//, "d"(mode) 25 | : "cc", "edi", "esi", "memory"); 26 | #endif 27 | return r; 28 | } 29 | 30 | // note : addr is unused for x86-64 since it is null (potentially unsafe, depend if register is initialized to 0 when program run) 31 | inline static unsigned int *sys_mmap(unsigned int *addr, unsigned long length, unsigned long prot, unsigned long flags, unsigned long fd) { 32 | #ifdef __x86_64 33 | register volatile int r10 __asm__ ("r10") = flags; register volatile int r8 __asm__ ("r8") = fd; unsigned int *r; 34 | __asm__ volatile ("syscall" : "=a" (r) : "a" (__NR_mmap)/*, "D" (addr)*/, "S" (length), "d" (prot), "r" (r10), "r" (r8) : "cc", "memory", "r11", "rcx"); 35 | return r; 36 | #else 37 | unsigned int args[2] = { (unsigned int)addr, 0 }; 38 | unsigned int *r; 39 | 40 | __asm__ __volatile__("push %%ebp\n" 41 | "movl 4(%%ebx), %%ebp\n" 42 | "movl 0(%%ebx), %%ebx\n" 43 | "int $0x80\n" 44 | "pop %%ebp\n" 45 | : "=a"(r) 46 | : "a"(__NR_mmap2), "b"(&args), 47 | "c"(length), "d"(prot), "S"(flags), "D"(fd)); 48 | 49 | return r; 50 | #endif 51 | } 52 | void _start() { 53 | // 0x00400007 : see elf64.s (this is /dev/fb0 string address packed in the ELF padding / ABI field) 54 | int fbfd = sys_open((char *)0x00400007, O_RDWR, 0); 55 | unsigned int *buffer = (unsigned int *)sys_mmap(0, FRAMEBUFFER_LENGTH, PROT_READ|PROT_WRITE, MAP_SHARED, fbfd); 56 | 57 | unsigned int x = WIDTH / 2; 58 | unsigned int y = HEIGHT / 2; 59 | 60 | unsigned int index = x + y * WIDTH; 61 | 62 | buffer[index] = 0xffffff; // white 63 | 64 | // note for float : if you use float constants in your C code, youll most likely want to load the data through pointers address (see below) 65 | // because float constants are loaded from memory and since we don't keep sections any float constants will vanish from the resulting binary 66 | // unless they are defined in elf64.s or elf32.s (just before the payload) and referenced via pointers in the C code, this allow even more fine controls over the data 67 | // Example (note : you must uncomment the constant definition line in elf64.s / elf32.s and add an offset of 4 in the Makefile) : 68 | // note : this is for 64 bits, the address must be changed for 32 bits 69 | // float my_float_constant = *(float*)0x00400078; 70 | } 71 | -------------------------------------------------------------------------------- /framebuffer_custom_elf/src/script_32.ld: -------------------------------------------------------------------------------- 1 | SECTIONS { 2 | . = 0x400056; 3 | 4 | combined . : AT(0x400056) ALIGN(1) SUBALIGN(1) { 5 | *(.text*) 6 | *(.data*) 7 | *(.rodata*) 8 | *(.bss*) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /framebuffer_custom_elf/src/script_64.ld: -------------------------------------------------------------------------------- 1 | SECTIONS { 2 | . = 0x400078; 3 | 4 | combined . : AT(0x400078) ALIGN(1) SUBALIGN(1) { 5 | *(.text*) 6 | *(.data*) 7 | *(.rodata*) 8 | *(.bss*) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /framebuffer_custom_elf/src/unpack_lzma.header: -------------------------------------------------------------------------------- 1 | HOME=/tmp/g;sed 1d $0|lzcat>~;chmod +x ~;clear;~;exit 2 | -------------------------------------------------------------------------------- /framebuffer_custom_elf_overlap/src/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | STANDARD_FLAGS=-std=c99 -pedantic -Wno-switch -Wno-conversion -Wno-uninitialized -Wno-strict-aliasing \ 3 | -fno-exceptions -ffast-math -fsingle-precision-constant -fno-ident \ 4 | -funsafe-math-optimizations -fvisibility=hidden -fmerge-all-constants \ 5 | -fno-align-functions -fno-align-loops -fno-math-errno #-march=native 6 | OPTI_FLAGS=-Os -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-stack-protector -ftree-vectorize -fopt-info-vec-optimized \ 7 | -fomit-frame-pointer -fno-math-errno -fdata-sections -ffunction-sections -fno-stack-check \ 8 | -nostartfiles -nodefaultlibs -no-pie -fno-plt -fno-pic -fno-unroll-loops -Winline 9 | LINKER_FLAGS=-Wl,--gc-sections \ 10 | -Wl,--build-id=none -z norelro -Wl,-z,noseparate-code -Wl,--no-eh-frame-hdr \ 11 | -Wl,--no-ld-generated-unwind-info -Wl,--hash-style=sysv \ 12 | -Wl,-z,nodynamic-undefined-weak 13 | NAME=fb 14 | LZMA_ARGS=--format=lzma -9 --extreme --lzma1=preset=9,lc=0,lp=0,pb=0,nice=32,depth=0,dict=16384 --keep 15 | 16 | all: 17 | rm -f $(NAME).lzma 18 | rm -f payload 19 | rm -f payload.bin 20 | rm -f nm_output 21 | $(eval LD_BITS=$(shell [ $(BITS) = 32 ] && echo "-m elf_i386" || echo "-m elf_x86_64")) 22 | $(CC) -o $(NAME) $(NAME).c -DWIDTH=$(WIDTH) -DHEIGHT=$(HEIGHT) -m$(BITS) $(STANDARD_FLAGS) $(OPTI_FLAGS) $(LINKER_FLAGS) 23 | # ugly 'fix' from seabios for newer version of ld which will fail when linking one executable to another (see: http://sourceware-org.1504.n7.nabble.com/recent-ld-built-for-x86-64-fails-to-accept-16bit-code-as-input-seabios-build-td641750.html) 24 | # original comment: Change e_type to ET_REL so that it can be used to link. Unlike GNU ld, lld does not allow an ET_EXEC input. 25 | # ld 2.30 does not have the problem but 2.36.1 does 26 | # NOTE : the entry point may change due to that so $(ENTRY) below is completely wrong and it result in a crash on my machine (vs ld 2.30) 27 | # don't know yet how to fix it cleanly except by just defining $(ENTRY) to be the address defined in the ld script (padded)... maybe check if that fix can be avoided ? 28 | #printf '\1' | dd of=$(NAME) conv=notrunc bs=1 seek=16 status=none 29 | # source : http://mainisusuallyafunction.blogspot.com/2015/01/151-byte-static-linux-binary-in-rust.html 30 | # 'smash all the sections together, with no alignment padding, then extract that section as a headerless binary blob' 31 | ld --gc-sections $(LD_BITS) -e _start -T script_$(BITS).ld -o payload $(NAME) 32 | objcopy -j combined -O binary payload payload.bin 33 | # determine the entry point address 34 | nm -f posix payload | grep '^_start ' | awk '{print $$3}' > nm_output 35 | # data offset (hex and uppercase) if any data is defined before the payload in elf64.s or elf32.s an offset must be added corresponding to the size of the data (so it compute the correct entry point) 36 | $(eval OFFSET=0) 37 | # get entry point address from nm_output (uppercase hex), compute offset if any and pad the result 38 | $(eval NM_OUTPUT=$(shell cat nm_output | tr '[a-z]' '[A-Z]')) 39 | $(eval NM_OUTPUT=$(shell perl -e 'print sprintf "%016s\n","$(NM_OUTPUT)"')) 40 | $(eval ENTRY=$(shell echo "obase=16;ibase=16;$(NM_OUTPUT) + $(OFFSET)" | bc)) 41 | $(eval ENTRY=$(shell perl -e 'print sprintf "%016s\n","$(ENTRY)"')) 42 | # build the final binary from the binary and custom ELF header 43 | nasm -f bin -o $(NAME) -D entry=0x$(ENTRY) elf$(BITS).s 44 | wc -c $(NAME) 45 | # comment the following three lines if you want raw ELF file (no stub / shell script / LZMA compression) 46 | #lzma $(LZMA_ARGS) $(NAME) 47 | #cat unpack_lzma.header $(NAME).lzma > $(NAME) 48 | #truncate -s -4 $(NAME) 49 | chmod +x $(NAME) 50 | rm -f $(NAME).lzma 51 | rm -f payload 52 | rm -f payload.bin 53 | wc -c $(NAME) 54 | mv $(NAME) ../$(NAME)_$(WIDTH)x$(HEIGHT)x$(BITS) 55 | chmod +x ../$(NAME)_$(WIDTH)x$(HEIGHT)x$(BITS) 56 | -------------------------------------------------------------------------------- /framebuffer_custom_elf_overlap/src/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | make WIDTH="1920" HEIGHT="1080" BITS="64" 3 | make WIDTH="800" HEIGHT="600" BITS="64" 4 | -------------------------------------------------------------------------------- /framebuffer_custom_elf_overlap/src/elf32.s: -------------------------------------------------------------------------------- 1 | bits 32 2 | org 0x00010000 3 | 4 | ehdr: 5 | db 0x7f, "ELF" ; magic 6 | dd 1 7 | dd 0 8 | dd $$ 9 | dw 2 10 | dw 3 11 | dd entry 12 | dd entry 13 | dd 4 14 | db "/dev/fb0" 15 | dw 0 ; dw 0x34 ; needed for end of string, does it break compat ? 16 | dw 0x20 17 | db 1 18 | db 0 ; note : seem mandatory 19 | ; dw 0 20 | ; dw 0 21 | ; dw 0 22 | 23 | ; see float note in the C code 24 | ; dd 0.5 25 | 26 | incbin "payload.bin" 27 | 28 | filesize equ $ - ehdr 29 | 30 | -------------------------------------------------------------------------------- /framebuffer_custom_elf_overlap/src/elf64.s: -------------------------------------------------------------------------------- 1 | bits 64 2 | org 0x100000000 3 | 4 | ehdr: 5 | db 0x7f, "ELF" ; magic 6 | db 2, 1, 1;, 0 ; 64-bits, little endian, version 1 7 | 8 | ; use unused ELF field to store framebuffer target string 9 | ; this also use the ABI target / version field (may be unsafe ?) 10 | db "/dev/fb0", 0 11 | 12 | dw 2 ; e_type = executable 13 | dw 0x3e ; e_machine = x86-64 14 | dd 1 ; e_version 15 | dd entry ; e_entry 16 | phdr: 17 | dd 1 ; p_type 18 | dd phdr - $$ ; e_phoff ; p_flags 19 | dd 0 ; p_offset 20 | dd 0 ; e_shoff 21 | dq $$ ; p_vaddr 22 | ; e_flags 23 | dw 0x40 ; e_ehsize ; p_paddr 24 | dw 0x38 ; e_phentsize 25 | dw 1 ; e_phnum 26 | dw 0 ; e_shentsize 27 | dq filesize ; e_shnum ; p_filesz 28 | ; e_shstrndx 29 | dq filesize ; p_memsz 30 | dq 0x00200000 ; p_align 31 | 32 | 33 | ; any data can also go here and are accessible in the C code through pointers but the 'entry' should be correcty updated (see Makefile) so it must have an offset added corresponding to the size of the data 34 | ; note : if you use float constants in your C code, youll most likely want to load them from here manually through pointers address 35 | ; because float constants are loaded from memory and since we don't use any sections any float constants will vanish from the resulting binary 36 | ; unless they are defined here and referenced via pointers in the C code 37 | 38 | ; dd 0.5 39 | 40 | incbin "payload.bin" 41 | 42 | filesize equ $ - ehdr 43 | 44 | -------------------------------------------------------------------------------- /framebuffer_custom_elf_overlap/src/fb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #ifdef __x86_64 4 | #include 5 | #else 6 | #include 7 | #endif 8 | 9 | // framebuffer settings (width / height / components should match actual framebuffer settings) 10 | #define FRAMEBUFFER_COMPONENTS 4 11 | #define FRAMEBUFFER_LENGTH (WIDTH * HEIGHT * FRAMEBUFFER_COMPONENTS) 12 | 13 | // note : mode argument is unused since it is null (potentially unsafe, depend if register is initialized to 0 when program run) 14 | inline static int sys_open(char *filepath, int flags, int mode) { 15 | int r; 16 | #ifdef __x86_64 17 | __asm__ volatile("syscall" 18 | : "=a"(r) 19 | : "0"(__NR_open), "D"(filepath), "S"(flags)//, "d"(mode) 20 | : "cc", "rcx", "r11", "memory"); 21 | #else 22 | __asm__ volatile("int $0x80" 23 | : "=a"(r) 24 | : "0"(__NR_open), "b"(filepath), "c"(flags)//, "d"(mode) 25 | : "cc", "edi", "esi", "memory"); 26 | #endif 27 | return r; 28 | } 29 | 30 | // note : addr is unused for x86-64 since it is null (potentially unsafe, depend if register is initialized to 0 when program run) 31 | inline static unsigned int *sys_mmap(unsigned int *addr, unsigned long length, unsigned long prot, unsigned long flags, unsigned long fd) { 32 | #ifdef __x86_64 33 | register volatile int r10 __asm__ ("r10") = flags; register volatile int r8 __asm__ ("r8") = fd; unsigned int *r; 34 | __asm__ volatile ("syscall" : "=a" (r) : "a" (__NR_mmap)/*, "D" (addr)*/, "S" (length), "d" (prot), "r" (r10), "r" (r8) : "cc", "memory", "r11", "rcx"); 35 | return r; 36 | #else 37 | unsigned int args[2] = { (unsigned int)addr, 0 }; 38 | unsigned int *r; 39 | 40 | __asm__ __volatile__("push %%ebp\n" 41 | "movl 4(%%ebx), %%ebp\n" 42 | "movl 0(%%ebx), %%ebx\n" 43 | "int $0x80\n" 44 | "pop %%ebp\n" 45 | : "=a"(r) 46 | : "a"(__NR_mmap2), "b"(&args), 47 | "c"(length), "d"(prot), "S"(flags), "D"(fd)); 48 | 49 | return r; 50 | #endif 51 | } 52 | void _start() { 53 | #ifdef __i386__ 54 | // 0x00010020 : see elf32.s (this is /dev/fb0 string address) 55 | int fbfd = sys_open((char *)0x00010020, O_RDWR, 0); 56 | #else 57 | // 0x100000007 : see elf64.s (this is /dev/fb0 string address packed in the ELF padding / ABI field) 58 | int fbfd = sys_open((char *)0x100000007, O_RDWR, 0); 59 | #endif 60 | unsigned int *buffer = (unsigned int *)sys_mmap(0, FRAMEBUFFER_LENGTH, PROT_READ|PROT_WRITE, MAP_SHARED, fbfd); 61 | 62 | unsigned int x = WIDTH / 2; 63 | unsigned int y = HEIGHT / 2; 64 | 65 | unsigned int index = x + y * WIDTH; 66 | 67 | buffer[index] = 0xffffff; // white 68 | 69 | // note for float : if you use float constants in your C code, youll most likely want to load the data through pointers address (see below) 70 | // because float constants are loaded from memory and since we don't keep sections any float constants will vanish from the resulting binary 71 | // unless they are defined in elf64.s or elf32.s (just before the payload) and referenced via pointers in the C code, this allow even more fine controls over the data 72 | // Example (note : you must uncomment the constant definition line in elf64.s / elf32.s and add an offset of 4 in the Makefile / linker file (.ld) for the entry point address) : 73 | // note : this is for 64 bits, the address must be changed for 32 bits 74 | // float my_float_constant = *(float*)0x100000054; 75 | } 76 | -------------------------------------------------------------------------------- /framebuffer_custom_elf_overlap/src/script_32.ld: -------------------------------------------------------------------------------- 1 | SECTIONS { 2 | . = 0x0001002E; 3 | 4 | combined . : AT(0x0001002E) ALIGN(1) SUBALIGN(1) { 5 | *(.text*) 6 | *(.data*) 7 | *(.rodata*) 8 | *(.bss*) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /framebuffer_custom_elf_overlap/src/script_64.ld: -------------------------------------------------------------------------------- 1 | SECTIONS { 2 | . = 0x100000054; 3 | 4 | combined . : AT(0x100000054) ALIGN(1) SUBALIGN(1) { 5 | *(.text*) 6 | *(.data*) 7 | *(.rodata*) 8 | *(.bss*) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /framebuffer_custom_elf_overlap/src/unpack_lzma.header: -------------------------------------------------------------------------------- 1 | HOME=/tmp/g;sed 1d $0|lzcat>~;chmod +x ~;clear;~;exit 2 | -------------------------------------------------------------------------------- /framebuffer_custom_elf_overlap_asminit32/src/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | STANDARD_FLAGS=-std=c99 -pedantic -Wno-switch -Wno-conversion -Wno-uninitialized -Wno-strict-aliasing \ 3 | -fno-exceptions -ffast-math -fsingle-precision-constant -fno-ident \ 4 | -funsafe-math-optimizations -fvisibility=hidden -fmerge-all-constants \ 5 | -fno-align-functions -fno-align-loops -fno-math-errno #-march=native 6 | OPTI_FLAGS=-Os -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-stack-protector -ftree-vectorize -fopt-info-vec-optimized \ 7 | -fomit-frame-pointer -fno-math-errno -fdata-sections -ffunction-sections -fno-stack-check \ 8 | -nostartfiles -nodefaultlibs -no-pie -fno-plt -fno-pic -fno-unroll-loops -Winline 9 | LINKER_FLAGS=-Wl,--gc-sections \ 10 | -Wl,--build-id=none -z norelro -Wl,-z,noseparate-code -Wl,--no-eh-frame-hdr \ 11 | -Wl,--no-ld-generated-unwind-info -Wl,--hash-style=sysv \ 12 | -Wl,-z,nodynamic-undefined-weak 13 | NAME=fb 14 | LZMA_ARGS=--format=lzma -9 --extreme --lzma1=preset=9,lc=0,lp=0,pb=0,nice=32,depth=0,dict=16384 --keep 15 | 16 | all: 17 | rm -f $(NAME).lzma 18 | rm -f payload 19 | rm -f payload.bin 20 | rm -f nm_output 21 | $(eval LD_BITS=$(shell [ $(BITS) = 32 ] && echo "-m elf_i386" || echo "-m elf_x86_64")) 22 | $(CC) -o $(NAME) $(NAME).c -DWIDTH=$(WIDTH) -DHEIGHT=$(HEIGHT) -m$(BITS) $(STANDARD_FLAGS) $(OPTI_FLAGS) $(LINKER_FLAGS) 23 | # ugly 'fix' from seabios for newer version of ld which will fail when linking one executable to another (see: http://sourceware-org.1504.n7.nabble.com/recent-ld-built-for-x86-64-fails-to-accept-16bit-code-as-input-seabios-build-td641750.html) 24 | # original comment: Change e_type to ET_REL so that it can be used to link. Unlike GNU ld, lld does not allow an ET_EXEC input. 25 | # ld 2.30 does not have the problem but 2.36.1 does 26 | # NOTE : the entry point may change due to that so $(ENTRY) below is completely wrong and it result in a crash on my machine (vs ld 2.30) 27 | # don't know yet how to fix it cleanly except by just defining $(ENTRY) to be the address defined in the ld script (padded)... maybe check if that fix can be avoided ? 28 | #printf '\1' | dd of=$(NAME) conv=notrunc bs=1 seek=16 status=none 29 | # source : http://mainisusuallyafunction.blogspot.com/2015/01/151-byte-static-linux-binary-in-rust.html 30 | # 'smash all the sections together, with no alignment padding, then extract that section as a headerless binary blob' 31 | ld --gc-sections $(LD_BITS) -e _start -T script_$(BITS).ld -o payload $(NAME) 32 | objcopy -j combined -O binary payload payload.bin 33 | # determine the entry point address 34 | nm -f posix payload | grep '^_start ' | awk '{print $$3}' > nm_output 35 | # data offset (hex and uppercase) if any data is defined before the payload in elf64.s or elf32.s an offset must be added corresponding to the size of the data (so it compute the correct entry point) 36 | $(eval OFFSET=0) 37 | # get entry point address from nm_output (uppercase hex), compute offset if any and pad the result 38 | $(eval NM_OUTPUT=$(shell cat nm_output | tr '[a-z]' '[A-Z]')) 39 | $(eval NM_OUTPUT=$(shell perl -e 'print sprintf "%016s\n","$(NM_OUTPUT)"')) 40 | $(eval ENTRY=$(shell echo "obase=16;ibase=16;$(NM_OUTPUT) + $(OFFSET)" | bc)) 41 | $(eval ENTRY=$(shell perl -e 'print sprintf "%016s\n","$(ENTRY)"')) 42 | # build the final binary from the binary and custom ELF header 43 | nasm -f bin -o $(NAME) -D width=$(WIDTH) -D height=$(HEIGHT) -D entry=0x$(ENTRY) elf$(BITS).s 44 | wc -c $(NAME) 45 | # comment the following three lines if you want raw ELF file (no stub / shell script / LZMA compression) 46 | #lzma $(LZMA_ARGS) $(NAME) 47 | #cat unpack_lzma.header $(NAME).lzma > $(NAME) 48 | #truncate -s -4 $(NAME) 49 | chmod +x $(NAME) 50 | rm -f $(NAME).lzma 51 | rm -f payload 52 | rm -f payload.bin 53 | wc -c $(NAME) 54 | mv $(NAME) ../$(NAME)_$(WIDTH)x$(HEIGHT)x$(BITS) 55 | chmod +x ../$(NAME)_$(WIDTH)x$(HEIGHT)x$(BITS) 56 | -------------------------------------------------------------------------------- /framebuffer_custom_elf_overlap_asminit32/src/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # note : only 32 bits is available 3 | make WIDTH="1920" HEIGHT="1080" BITS="32" 4 | make WIDTH="800" HEIGHT="600" BITS="32" 5 | -------------------------------------------------------------------------------- /framebuffer_custom_elf_overlap_asminit32/src/elf32.s: -------------------------------------------------------------------------------- 1 | bits 32 2 | org 0x00010000 3 | 4 | ehdr: 5 | db 0x7f, "ELF" 6 | dd 1 7 | dd 0 8 | dd $$ 9 | dw 2 10 | dw 3 11 | dd entry 12 | dd entry 13 | dd 4 14 | db "/dev/fb0",0 15 | 16 | ; based on 'lintro' 128 bytes intro by frag/fsqrt: https://www.pouet.net/prod.php?which=58560 17 | mov ebx, 10020h 18 | mov cl, 2 19 | mov al, 5 ;e_shstrndx 20 | ; end of elf header 21 | 22 | ; open("/dev/fb0", O_RDRW); 23 | int 80h ; eax <- fd 24 | 25 | ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0); 26 | push edx ;edx = 0 27 | push eax ;fd 28 | push byte 1 ;MAP_SHARED 29 | mov al, 90 30 | push eax ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ 31 | push width*height*4 ;buffer size 32 | push edx ;NULL 33 | mov ebx, esp ;args pointer 34 | int 80h ;eax <- buffer pointer 35 | 36 | incbin "payload.bin" 37 | 38 | filesize equ $ - ehdr 39 | 40 | -------------------------------------------------------------------------------- /framebuffer_custom_elf_overlap_asminit32/src/fb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #ifdef __x86_64 4 | #include 5 | #else 6 | #include 7 | #endif 8 | 9 | // framebuffer settings (width / height / components should match actual framebuffer settings) 10 | #define FRAMEBUFFER_COMPONENTS 4 11 | #define FRAMEBUFFER_LENGTH (WIDTH * HEIGHT * FRAMEBUFFER_COMPONENTS) 12 | 13 | void _start() { 14 | #ifdef __i386__ 15 | // see elf32.s (all C framebuffer init code was replaced by optimized x86 assembly, the buffer pointer is into eax at this point) 16 | register unsigned int *buffer __asm__("eax"); 17 | #endif 18 | 19 | unsigned int x = WIDTH / 2; 20 | unsigned int y = HEIGHT / 2; 21 | 22 | unsigned int index = x + y * WIDTH; 23 | 24 | buffer[index] = 0xffffff; // white 25 | } 26 | -------------------------------------------------------------------------------- /framebuffer_custom_elf_overlap_asminit32/src/script_32.ld: -------------------------------------------------------------------------------- 1 | SECTIONS { 2 | . = 0x00010029; 3 | 4 | combined . : AT(0x00010029) ALIGN(1) SUBALIGN(1) { 5 | *(.text*) 6 | *(.data*) 7 | *(.rodata*) 8 | *(.bss*) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /framebuffer_custom_elf_overlap_pwrite64/src/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | STANDARD_FLAGS=-std=c99 -pedantic -Wno-switch -Wno-conversion -Wno-uninitialized -Wno-strict-aliasing \ 3 | -fno-exceptions -ffast-math -fsingle-precision-constant -fno-ident \ 4 | -funsafe-math-optimizations -fvisibility=hidden -fmerge-all-constants \ 5 | -fno-align-functions -fno-align-loops -fno-math-errno #-march=native 6 | OPTI_FLAGS=-Os -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-stack-protector -ftree-vectorize -fopt-info-vec-optimized \ 7 | -fomit-frame-pointer -fno-math-errno -fdata-sections -ffunction-sections -fno-stack-check \ 8 | -nostartfiles -nodefaultlibs -no-pie -fno-plt -fno-pic -fno-unroll-loops -Winline 9 | LINKER_FLAGS=-Wl,--gc-sections \ 10 | -Wl,--build-id=none -z norelro -Wl,-z,noseparate-code -Wl,--no-eh-frame-hdr \ 11 | -Wl,--no-ld-generated-unwind-info -Wl,--hash-style=sysv \ 12 | -Wl,-z,nodynamic-undefined-weak 13 | NAME=fb 14 | LZMA_ARGS=--format=lzma -9 --extreme --lzma1=preset=9,lc=0,lp=0,pb=0,nice=32,depth=0,dict=16384 --keep 15 | 16 | all: 17 | rm -f $(NAME).lzma 18 | rm -f payload 19 | rm -f payload.bin 20 | rm -f nm_output 21 | $(eval LD_BITS=$(shell [ $(BITS) = 32 ] && echo "-m elf_i386" || echo "-m elf_x86_64")) 22 | $(CC) -o $(NAME) $(NAME).c -DWIDTH=$(WIDTH) -DHEIGHT=$(HEIGHT) -m$(BITS) $(STANDARD_FLAGS) $(OPTI_FLAGS) $(LINKER_FLAGS) 23 | # ugly 'fix' from seabios for newer version of ld which will fail when linking one executable to another (see: http://sourceware-org.1504.n7.nabble.com/recent-ld-built-for-x86-64-fails-to-accept-16bit-code-as-input-seabios-build-td641750.html) 24 | # original comment: Change e_type to ET_REL so that it can be used to link. Unlike GNU ld, lld does not allow an ET_EXEC input. 25 | # ld 2.30 does not have the problem but 2.36.1 does 26 | # NOTE : the entry point may change due to that so $(ENTRY) below is completely wrong and it result in a crash on my machine (vs ld 2.30) 27 | # don't know yet how to fix it cleanly except by just defining $(ENTRY) to be the address defined in the ld script (padded)... maybe check if that fix can be avoided ? 28 | #printf '\1' | dd of=$(NAME) conv=notrunc bs=1 seek=16 status=none 29 | # source : http://mainisusuallyafunction.blogspot.com/2015/01/151-byte-static-linux-binary-in-rust.html 30 | # 'smash all the sections together, with no alignment padding, then extract that section as a headerless binary blob' 31 | ld --gc-sections $(LD_BITS) -e _start -T script_$(BITS).ld -o payload $(NAME) 32 | objcopy -j combined -O binary payload payload.bin 33 | # determine the entry point address 34 | nm -f posix payload | grep '^_start ' | awk '{print $$3}' > nm_output 35 | # data offset (hex and uppercase) if any data is defined before the payload in elf64.s or elf32.s an offset must be added corresponding to the size of the data (so it compute the correct entry point) 36 | $(eval OFFSET=-5) 37 | # get entry point address from nm_output (uppercase hex), compute offset if any and pad the result 38 | $(eval NM_OUTPUT=$(shell cat nm_output | tr '[a-z]' '[A-Z]')) 39 | $(eval NM_OUTPUT=$(shell perl -e 'print sprintf "%016s\n","$(NM_OUTPUT)"')) 40 | $(eval ENTRY=$(shell echo "obase=16;ibase=16;$(NM_OUTPUT) + $(OFFSET)" | bc)) 41 | $(eval ENTRY=$(shell perl -e 'print sprintf "%016s\n","$(ENTRY)"')) 42 | # build the final binary from the binary and custom ELF header 43 | nasm -f bin -o $(NAME) -D width=$(WIDTH) -D height=$(HEIGHT) -D entry=0x$(ENTRY) elf$(BITS).s 44 | wc -c $(NAME) 45 | # comment the following three lines if you want raw ELF file (no stub / shell script / LZMA compression) 46 | #lzma $(LZMA_ARGS) $(NAME) 47 | #cat unpack_lzma.header $(NAME).lzma > $(NAME) 48 | #truncate -s -4 $(NAME) 49 | chmod +x $(NAME) 50 | rm -f $(NAME).lzma 51 | rm -f payload 52 | rm -f payload.bin 53 | wc -c $(NAME) 54 | mv $(NAME) ../$(NAME)_$(WIDTH)x$(HEIGHT)x$(BITS) 55 | chmod +x ../$(NAME)_$(WIDTH)x$(HEIGHT)x$(BITS) 56 | -------------------------------------------------------------------------------- /framebuffer_custom_elf_overlap_pwrite64/src/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # note : only 32 bits is available 3 | make WIDTH="1920" HEIGHT="1080" BITS="32" 4 | make WIDTH="800" HEIGHT="600" BITS="32" 5 | -------------------------------------------------------------------------------- /framebuffer_custom_elf_overlap_pwrite64/src/elf32.s: -------------------------------------------------------------------------------- 1 | bits 32 2 | org 0x00010000 3 | 4 | ehdr: 5 | db 0x7f, "ELF" 6 | dd 1 7 | dd 0 8 | dd $$ 9 | dw 2 10 | dw 3 11 | dd entry 12 | dd entry 13 | dd 4 14 | db "/dev/fb0",0 15 | 16 | ; based on 'lintro' 128 bytes intro by frag/fsqrt: https://www.pouet.net/prod.php?which=58560 17 | mov ebx, 10020h 18 | inc ecx 19 | mov al, 5 ;e_shstrndx 20 | ; end of elf header 21 | 22 | ; open("/dev/fb0", O_RDRW); 23 | int 80h ; eax <- fd 24 | 25 | ; make more space on the stack for display buffer (note : max size may be limited) 26 | mov ebp, width * height * 4 27 | sub esp, ebp 28 | 29 | incbin "payload.bin" 30 | 31 | filesize equ $ - ehdr 32 | 33 | -------------------------------------------------------------------------------- /framebuffer_custom_elf_overlap_pwrite64/src/fb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #ifdef __x86_64 4 | #include 5 | #else 6 | #include 7 | #endif 8 | 9 | // framebuffer settings (width / height / components should match actual framebuffer settings) 10 | #define FRAMEBUFFER_COMPONENTS 4 11 | #define FRAMEBUFFER_LENGTH (WIDTH * HEIGHT * FRAMEBUFFER_COMPONENTS) 12 | 13 | void _start() { 14 | #ifdef __i386__ 15 | // see elf32.s (all C framebuffer init code was replaced by optimized x86 assembly, the buffer pointer is into sp at this point) 16 | register unsigned int *buffer __asm__("sp"); 17 | #endif 18 | 19 | unsigned int x = WIDTH / 2; 20 | unsigned int y = HEIGHT / 2; 21 | 22 | unsigned int index = x + y * WIDTH; 23 | 24 | buffer[index] = 0xffffff; // white 25 | 26 | /* note : can do some cheap scrolling (screen offset) / glitch effects by passing different parameters instead of zeroing out registers 27 | original: 28 | mov ecx,esp ; buffer ptr 29 | mov edx,ebp ; screen size 30 | xor esi,esi ; seek to beginning of screen 31 | xor edi,edi 32 | mov ebx,3 ; fd of framebuffer 33 | mov eax,0xb5 ; pwrite64 34 | int 0x80 ; pwrite64 to framebuffer 35 | 36 | optimized: 37 | ; pwrite64 38 | mov ecx,esp ; buffer ptr 39 | mov edx,ebp ; screen size 40 | xor esi,esi ; seek to beginning of screen 41 | xor edi,edi 42 | push 3 43 | pop ebx 44 | xor eax,eax 45 | mov al,0xb5 46 | int 0x80 ; pwrite64 to framebuffer 47 | */ 48 | #ifdef __i386__ 49 | __asm__ volatile (".byte 0x89,0xe1,0x89,0xea,0x31,0xf6,0x31,0xff,0x6a,0x03,0x5b,0x31,0xc0,0xb0,0xb5,0xcd,0x80"); 50 | #endif 51 | } 52 | -------------------------------------------------------------------------------- /framebuffer_custom_elf_overlap_pwrite64/src/script_32.ld: -------------------------------------------------------------------------------- 1 | SECTIONS { 2 | . = 0x0001002E; 3 | 4 | combined . : AT(0x0001002E) ALIGN(1) SUBALIGN(1) { 5 | *(.text*) 6 | *(.data*) 7 | *(.rodata*) 8 | *(.bss*) 9 | } 10 | } 11 | --------------------------------------------------------------------------------