<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>http://www.sizecoding.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Byteobserver</id>
		<title>SizeCoding - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="http://www.sizecoding.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Byteobserver"/>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/wiki/Special:Contributions/Byteobserver"/>
		<updated>2026-05-03T22:12:19Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.27.0</generator>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=1354</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=1354"/>
				<updated>2024-03-15T17:32:26Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Additional Resources */ add Tiny bitfield based text renderer&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old XOR pattern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method (method 1) is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method (method 2) uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers. Method 3, which saves some bytes over method 2 (especially when combined with visuals), is to use a shell based loader script.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pick apart the shell loader. Remember that in bash, $_ is the last argument passed to the previous command,&lt;br /&gt;
and $0 is the filename of the current executable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=shell&amp;gt;&lt;br /&gt;
cp $0 /tmp # copy the intro to /tmp&lt;br /&gt;
sed -i 1d $_/$0 # remove the first line from the copy with sed (aka remove the loader)&lt;br /&gt;
$_|aplay # execute the intro&lt;br /&gt;
rm $_ # remove the copy&lt;br /&gt;
exit # (so that the binary data which follows doesn't get executed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 10 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_&amp;lt;&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 or mmap directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Syncing audio with visuals is unfortunately not as easy as one would hope. Unlike many oldskool platforms, you can't just write audio and video data in your main loop and have everything work out nicely. The reason for this is that the audio is buffered with a relatively large buffer size, which is not easy to change. The effect of this is that audio writes will succeed instantly without blocking until about 1 second of audio has been written, and then the next write will block for about 1 second. This process then repeats. As you can imagine this means the visuals will run at about 1 FPS.&lt;br /&gt;
&lt;br /&gt;
Even if you know the exact audio buffer size, it doesn't really help to synchronize things because the synchronization will be dependent on the CPU speed (as well as how much CPU time background processes are taking, etc). In order to synchronize things properly you will need to use a timer. See the Limiting FPS section below for how to do this. You are looking at a cost of about 22 bytes for this timer at the very least.&lt;br /&gt;
&lt;br /&gt;
After you have a timer set up, you just need to decide on a target FPS and calculate how much audio you should write per frame. The general formula that you should write &amp;lt;tt&amp;gt;rate * channels * sample width in bytes / FPS&amp;lt;/tt&amp;gt; bytes per frame. For example, if your intro runs at 50 FPS and your audio uses 16bit samples in stereo at 8000Hz, then you should write &amp;lt;tt&amp;gt;8000*2*2/50 = 640&amp;lt;/tt&amp;gt; bytes of audio for every frame.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous Techniques ==&lt;br /&gt;
&lt;br /&gt;
=== Limiting FPS ===&lt;br /&gt;
&lt;br /&gt;
The framebuffer device /dev/fb0 will allow you to write to it as quickly as your CPU can manage,&lt;br /&gt;
so your intro can run at different speeds depending on the CPU speed. To correct this, you can use&lt;br /&gt;
a timer to limit FPS. Beyond limiting the frame rate, using a timer is seemingly necessary if you&lt;br /&gt;
want to have synchronized sound and graphics (but more research is needed).&lt;br /&gt;
&lt;br /&gt;
We will describe two approaches to setting up a timer. The first method uses the &amp;lt;tt&amp;gt;sys_timerfd_*&amp;lt;/tt&amp;gt;&lt;br /&gt;
syscalls, which creates a file descriptor where reads block until the timer expires.&lt;br /&gt;
The second uses the &amp;lt;tt&amp;gt;sys_timer_*&amp;lt;/tt&amp;gt; syscalls, which send signals that can be caught by installing a signal handler.&lt;br /&gt;
The first method is usually smaller.&lt;br /&gt;
&lt;br /&gt;
==== Method 1: timerfd ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assume this is placed at the beginning of the program (all registers zeroed)&lt;br /&gt;
timer:&lt;br /&gt;
    ; NEW: smaller 18-byte setup!&lt;br /&gt;
    add ax,0x142&lt;br /&gt;
    push ecx&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    jns timer&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,3 ; read syscall&lt;br /&gt;
    mov ebx,eax ; file descriptor of timer&lt;br /&gt;
    mov dl,8 ; num bytes to read, edx can be any value &amp;gt;= 8&lt;br /&gt;
    mov ecx,esp ; write timer expiration info to the stack&lt;br /&gt;
    int 0x80 ; blocks until the next frame&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Method 2: signal handler ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming this is at the beginning of the program (all registers zeroed)&lt;br /&gt;
    call callback ; set up signal handler initially&lt;br /&gt;
&lt;br /&gt;
    ; assume eax &amp;lt; 65536, ebx = 1&lt;br /&gt;
    mov ax,0x103 ; timer_create&lt;br /&gt;
    dec ebx&lt;br /&gt;
    push ebx&lt;br /&gt;
    push 1 ; SIGHUP&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov ax,0x104 ; timer_settime&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp $ ; loop forever&lt;br /&gt;
&lt;br /&gt;
callback:&lt;br /&gt;
    ; assume eax &amp;lt; 256, ebx = 0&lt;br /&gt;
    mov al,0x30 ; signal&lt;br /&gt;
    inc ebx&lt;br /&gt;
    mov ecx,callback&lt;br /&gt;
    int 0x80 ; (re)install signal handler&lt;br /&gt;
    ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Allocating memory ===&lt;br /&gt;
&lt;br /&gt;
On many Linux distros, the stack size is limited to 8MB by default. If this is not enough for your intro,&lt;br /&gt;
it is possible to increase this stack limit or to allocate memory in the data segment.&lt;br /&gt;
&lt;br /&gt;
To allocate space in the data segment, you can use the brk system call (0x2d).&lt;br /&gt;
This call takes in a memory address and attempts to set the value of the current ''program break'' to that address,&lt;br /&gt;
then returns the new address. The program break is the smallest memory address that is beyond the data segment.&lt;br /&gt;
By default, the data segment is zero bytes long.&lt;br /&gt;
Unfortunately, on modern systems, the default value of the program break is &lt;br /&gt;
randomized, so you can't just simply call brk with the amount of memory you want.&lt;br /&gt;
Instead, you have to call brk with an address of zero to get the current program break,&lt;br /&gt;
then add the amount of memory you want and call brk with the new address.&lt;br /&gt;
The following code does this in 15 bytes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    xchg eax,ebx&lt;br /&gt;
    add ebx,0x1000000 ; allocate 16MB&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    ; eax now contains the address of the program break, i.e.,&lt;br /&gt;
    ; you can use memory from eax-0x1000000 to eax-1 (inclusive)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To increase the stack size limit, you can use the setrlimit (0x4b) system call.&lt;br /&gt;
The following 11-byte snippet will remove the stack size limit completely.&lt;br /&gt;
Note that in some cases the user will not have permission to do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    dec ecx ; ecx = -1 aka set size to 'unlimited'&lt;br /&gt;
    push ecx&lt;br /&gt;
    push ecx&lt;br /&gt;
    mov bl,3 ; RLIMIT_STACK&lt;br /&gt;
    mov ecx,esp ; pointer to data for call&lt;br /&gt;
    mov al,0x4b ; setrlimit&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Self modifying code ===&lt;br /&gt;
With the tiny ELF header we've been using, the code segment is not writable, and unfortunately we need to sacrifice some bytes to make it so.&lt;br /&gt;
So, in many cases it's better to avoid using self modifying code. But, if you want to try it out, there are two ways to go about it.&lt;br /&gt;
In the ELF header, the p_flags field stores the access permissions of the code memory (1=execute, 2=write, 4=read).&lt;br /&gt;
In the tiny header, p_flags overlaps with e_phoff, and e_phoff (the offset of the program header from the beginning of the file) needs to be 4.&lt;br /&gt;
So, the only option for p_flags is read-only (turns out that the execute bit doesn't matter, and it will be executable anyways).&lt;br /&gt;
To make the code writable, we have to change p_flags to 7 (6 and 3 also accomplish the same thing because some are implied by others).&lt;br /&gt;
To do this we can either use a less overlapped header, or we can use the mprotect syscall to change&lt;br /&gt;
the permissions.&lt;br /&gt;
&lt;br /&gt;
See here for examples of some headers that allow you to change p_flags: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html&lt;br /&gt;
&lt;br /&gt;
The mprotect method is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov eax,0x7d ; mprotect&lt;br /&gt;
    mov ebx,$$ ; start address to change permissions for&lt;br /&gt;
    mov ecx,0x1000 ; number of bytes to change&lt;br /&gt;
    mov edx,7 ; new permissions&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Getting the screen size ===&lt;br /&gt;
&lt;br /&gt;
A lot of Linux intros have the screen resolution hard-coded, and some include many executables in the release, each for a different screen resolution. If you have enough space, you can easily get the screen resolution using the &amp;lt;tt&amp;gt;ioctl&amp;lt;/tt&amp;gt; syscall.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x36 ; ioctl&lt;br /&gt;
    mov ebx,0   ; ***PUT THE FILE DESCRIPTOR FOR /dev/fb0 HERE***&lt;br /&gt;
    xor ecx,ecx&lt;br /&gt;
    mov ch,0x46 ; FBIOGET_VSCREENINFO&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
    pop eax ; eax = horizontal resolution in pixels&lt;br /&gt;
    pop ebx ; ebx = vertical resolution in pixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For more information about what you can do with ioctl on the framebuffer, see here: https://www.kernel.org/doc/html/latest/fb/api.html&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
* [https://www.onirom.fr/wiki/blog/25-09-2022_tiny_bitfield_based_text_renderer/ Tiny bitfield based text renderer]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=1011</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=1011"/>
				<updated>2022-02-11T00:28:22Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Method 1: timerfd */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old XOR pattern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method (method 1) is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method (method 2) uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers. Method 3, which saves some bytes over method 2 (especially when combined with visuals), is to use a shell based loader script.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pick apart the shell loader. Remember that in bash, $_ is the last argument passed to the previous command,&lt;br /&gt;
and $0 is the filename of the current executable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=shell&amp;gt;&lt;br /&gt;
cp $0 /tmp # copy the intro to /tmp&lt;br /&gt;
sed -i 1d $_/$0 # remove the first line from the copy with sed (aka remove the loader)&lt;br /&gt;
$_|aplay # execute the intro&lt;br /&gt;
rm $_ # remove the copy&lt;br /&gt;
exit # (so that the binary data which follows doesn't get executed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 10 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_&amp;lt;&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 or mmap directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Syncing audio with visuals is unfortunately not as easy as one would hope. Unlike many oldskool platforms, you can't just write audio and video data in your main loop and have everything work out nicely. The reason for this is that the audio is buffered with a relatively large buffer size, which is not easy to change. The effect of this is that audio writes will succeed instantly without blocking until about 1 second of audio has been written, and then the next write will block for about 1 second. This process then repeats. As you can imagine this means the visuals will run at about 1 FPS.&lt;br /&gt;
&lt;br /&gt;
Even if you know the exact audio buffer size, it doesn't really help to synchronize things because the synchronization will be dependent on the CPU speed (as well as how much CPU time background processes are taking, etc). In order to synchronize things properly you will need to use a timer. See the Limiting FPS section below for how to do this. You are looking at a cost of about 22 bytes for this timer at the very least.&lt;br /&gt;
&lt;br /&gt;
After you have a timer set up, you just need to decide on a target FPS and calculate how much audio you should write per frame. The general formula that you should write &amp;lt;tt&amp;gt;rate * channels * sample width in bytes / FPS&amp;lt;/tt&amp;gt; bytes per frame. For example, if your intro runs at 50 FPS and your audio uses 16bit samples in stereo at 8000Hz, then you should write &amp;lt;tt&amp;gt;8000*2*2/50 = 640&amp;lt;/tt&amp;gt; bytes of audio for every frame.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous Techniques ==&lt;br /&gt;
&lt;br /&gt;
=== Limiting FPS ===&lt;br /&gt;
&lt;br /&gt;
The framebuffer device /dev/fb0 will allow you to write to it as quickly as your CPU can manage,&lt;br /&gt;
so your intro can run at different speeds depending on the CPU speed. To correct this, you can use&lt;br /&gt;
a timer to limit FPS. Beyond limiting the frame rate, using a timer is seemingly necessary if you&lt;br /&gt;
want to have synchronized sound and graphics (but more research is needed).&lt;br /&gt;
&lt;br /&gt;
We will describe two approaches to setting up a timer. The first method uses the &amp;lt;tt&amp;gt;sys_timerfd_*&amp;lt;/tt&amp;gt;&lt;br /&gt;
syscalls, which creates a file descriptor where reads block until the timer expires.&lt;br /&gt;
The second uses the &amp;lt;tt&amp;gt;sys_timer_*&amp;lt;/tt&amp;gt; syscalls, which send signals that can be caught by installing a signal handler.&lt;br /&gt;
The first method is usually smaller.&lt;br /&gt;
&lt;br /&gt;
==== Method 1: timerfd ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assume this is placed at the beginning of the program (all registers zeroed)&lt;br /&gt;
timer:&lt;br /&gt;
    ; NEW: smaller 18-byte setup!&lt;br /&gt;
    add ax,0x142&lt;br /&gt;
    push ecx&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    jns timer&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,3 ; read syscall&lt;br /&gt;
    mov ebx,eax ; file descriptor of timer&lt;br /&gt;
    mov dl,8 ; num bytes to read, edx can be any value &amp;gt;= 8&lt;br /&gt;
    mov ecx,esp ; write timer expiration info to the stack&lt;br /&gt;
    int 0x80 ; blocks until the next frame&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Method 2: signal handler ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming this is at the beginning of the program (all registers zeroed)&lt;br /&gt;
    call callback ; set up signal handler initially&lt;br /&gt;
&lt;br /&gt;
    ; assume eax &amp;lt; 65536, ebx = 1&lt;br /&gt;
    mov ax,0x103 ; timer_create&lt;br /&gt;
    dec ebx&lt;br /&gt;
    push ebx&lt;br /&gt;
    push 1 ; SIGHUP&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov ax,0x104 ; timer_settime&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp $ ; loop forever&lt;br /&gt;
&lt;br /&gt;
callback:&lt;br /&gt;
    ; assume eax &amp;lt; 256, ebx = 0&lt;br /&gt;
    mov al,0x30 ; signal&lt;br /&gt;
    inc ebx&lt;br /&gt;
    mov ecx,callback&lt;br /&gt;
    int 0x80 ; (re)install signal handler&lt;br /&gt;
    ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Allocating memory ===&lt;br /&gt;
&lt;br /&gt;
On many Linux distros, the stack size is limited to 8MB by default. If this is not enough for your intro,&lt;br /&gt;
it is possible to increase this stack limit or to allocate memory in the data segment.&lt;br /&gt;
&lt;br /&gt;
To allocate space in the data segment, you can use the brk system call (0x2d).&lt;br /&gt;
This call takes in a memory address and attempts to set the value of the current ''program break'' to that address,&lt;br /&gt;
then returns the new address. The program break is the smallest memory address that is beyond the data segment.&lt;br /&gt;
By default, the data segment is zero bytes long.&lt;br /&gt;
Unfortunately, on modern systems, the default value of the program break is &lt;br /&gt;
randomized, so you can't just simply call brk with the amount of memory you want.&lt;br /&gt;
Instead, you have to call brk with an address of zero to get the current program break,&lt;br /&gt;
then add the amount of memory you want and call brk with the new address.&lt;br /&gt;
The following code does this in 15 bytes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    xchg eax,ebx&lt;br /&gt;
    add ebx,0x1000000 ; allocate 16MB&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    ; eax now contains the address of the program break, i.e.,&lt;br /&gt;
    ; you can use memory from eax-0x1000000 to eax-1 (inclusive)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To increase the stack size limit, you can use the setrlimit (0x4b) system call.&lt;br /&gt;
The following 11-byte snippet will remove the stack size limit completely.&lt;br /&gt;
Note that in some cases the user will not have permission to do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    dec ecx ; ecx = -1 aka set size to 'unlimited'&lt;br /&gt;
    push ecx&lt;br /&gt;
    push ecx&lt;br /&gt;
    mov bl,3 ; RLIMIT_STACK&lt;br /&gt;
    mov ecx,esp ; pointer to data for call&lt;br /&gt;
    mov al,0x4b ; setrlimit&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Self modifying code ===&lt;br /&gt;
With the tiny ELF header we've been using, the code segment is not writable, and unfortunately we need to sacrifice some bytes to make it so.&lt;br /&gt;
So, in many cases it's better to avoid using self modifying code. But, if you want to try it out, there are two ways to go about it.&lt;br /&gt;
In the ELF header, the p_flags field stores the access permissions of the code memory (1=execute, 2=write, 4=read).&lt;br /&gt;
In the tiny header, p_flags overlaps with e_phoff, and e_phoff (the offset of the program header from the beginning of the file) needs to be 4.&lt;br /&gt;
So, the only option for p_flags is read-only (turns out that the execute bit doesn't matter, and it will be executable anyways).&lt;br /&gt;
To make the code writable, we have to change p_flags to 7 (6 and 3 also accomplish the same thing because some are implied by others).&lt;br /&gt;
To do this we can either use a less overlapped header, or we can use the mprotect syscall to change&lt;br /&gt;
the permissions.&lt;br /&gt;
&lt;br /&gt;
See here for examples of some headers that allow you to change p_flags: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html&lt;br /&gt;
&lt;br /&gt;
The mprotect method is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov eax,0x7d ; mprotect&lt;br /&gt;
    mov ebx,$$ ; start address to change permissions for&lt;br /&gt;
    mov ecx,0x1000 ; number of bytes to change&lt;br /&gt;
    mov edx,7 ; new permissions&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Getting the screen size ===&lt;br /&gt;
&lt;br /&gt;
A lot of Linux intros have the screen resolution hard-coded, and some include many executables in the release, each for a different screen resolution. If you have enough space, you can easily get the screen resolution using the &amp;lt;tt&amp;gt;ioctl&amp;lt;/tt&amp;gt; syscall.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x36 ; ioctl&lt;br /&gt;
    mov ebx,0   ; ***PUT THE FILE DESCRIPTOR FOR /dev/fb0 HERE***&lt;br /&gt;
    xor ecx,ecx&lt;br /&gt;
    mov ch,0x46 ; FBIOGET_VSCREENINFO&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
    pop eax ; eax = horizontal resolution in pixels&lt;br /&gt;
    pop ebx ; ebx = vertical resolution in pixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For more information about what you can do with ioctl on the framebuffer, see here: https://www.kernel.org/doc/html/latest/fb/api.html&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=1010</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=1010"/>
				<updated>2022-02-10T16:58:31Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Method 1: timerfd */ smaller setup code for timerfd&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old XOR pattern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method (method 1) is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method (method 2) uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers. Method 3, which saves some bytes over method 2 (especially when combined with visuals), is to use a shell based loader script.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pick apart the shell loader. Remember that in bash, $_ is the last argument passed to the previous command,&lt;br /&gt;
and $0 is the filename of the current executable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=shell&amp;gt;&lt;br /&gt;
cp $0 /tmp # copy the intro to /tmp&lt;br /&gt;
sed -i 1d $_/$0 # remove the first line from the copy with sed (aka remove the loader)&lt;br /&gt;
$_|aplay # execute the intro&lt;br /&gt;
rm $_ # remove the copy&lt;br /&gt;
exit # (so that the binary data which follows doesn't get executed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 10 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_&amp;lt;&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 or mmap directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Syncing audio with visuals is unfortunately not as easy as one would hope. Unlike many oldskool platforms, you can't just write audio and video data in your main loop and have everything work out nicely. The reason for this is that the audio is buffered with a relatively large buffer size, which is not easy to change. The effect of this is that audio writes will succeed instantly without blocking until about 1 second of audio has been written, and then the next write will block for about 1 second. This process then repeats. As you can imagine this means the visuals will run at about 1 FPS.&lt;br /&gt;
&lt;br /&gt;
Even if you know the exact audio buffer size, it doesn't really help to synchronize things because the synchronization will be dependent on the CPU speed (as well as how much CPU time background processes are taking, etc). In order to synchronize things properly you will need to use a timer. See the Limiting FPS section below for how to do this. You are looking at a cost of about 22 bytes for this timer at the very least.&lt;br /&gt;
&lt;br /&gt;
After you have a timer set up, you just need to decide on a target FPS and calculate how much audio you should write per frame. The general formula that you should write &amp;lt;tt&amp;gt;rate * channels * sample width in bytes / FPS&amp;lt;/tt&amp;gt; bytes per frame. For example, if your intro runs at 50 FPS and your audio uses 16bit samples in stereo at 8000Hz, then you should write &amp;lt;tt&amp;gt;8000*2*2/50 = 640&amp;lt;/tt&amp;gt; bytes of audio for every frame.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous Techniques ==&lt;br /&gt;
&lt;br /&gt;
=== Limiting FPS ===&lt;br /&gt;
&lt;br /&gt;
The framebuffer device /dev/fb0 will allow you to write to it as quickly as your CPU can manage,&lt;br /&gt;
so your intro can run at different speeds depending on the CPU speed. To correct this, you can use&lt;br /&gt;
a timer to limit FPS. Beyond limiting the frame rate, using a timer is seemingly necessary if you&lt;br /&gt;
want to have synchronized sound and graphics (but more research is needed).&lt;br /&gt;
&lt;br /&gt;
We will describe two approaches to setting up a timer. The first method uses the &amp;lt;tt&amp;gt;sys_timerfd_*&amp;lt;/tt&amp;gt;&lt;br /&gt;
syscalls, which creates a file descriptor where reads block until the timer expires.&lt;br /&gt;
The second uses the &amp;lt;tt&amp;gt;sys_timer_*&amp;lt;/tt&amp;gt; syscalls, which send signals that can be caught by installing a signal handler.&lt;br /&gt;
The first method is usually smaller.&lt;br /&gt;
&lt;br /&gt;
==== Method 1: timerfd ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assume this is placed at the beginning of the program (all registers zeroed)&lt;br /&gt;
timer:&lt;br /&gt;
    ; NEW: smaller 18-byte setup!&lt;br /&gt;
    add ax,0x142&lt;br /&gt;
    push ecx&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    jns timer&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,3 ; read syscall&lt;br /&gt;
    mov ebx,eax ; file descriptor of timer&lt;br /&gt;
    mov dl,8 ; num bytes to read, edx can be any value &amp;gt;= 8&lt;br /&gt;
    mov ecx,esp ; write timer expiration info to the stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Method 2: signal handler ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming this is at the beginning of the program (all registers zeroed)&lt;br /&gt;
    call callback ; set up signal handler initially&lt;br /&gt;
&lt;br /&gt;
    ; assume eax &amp;lt; 65536, ebx = 1&lt;br /&gt;
    mov ax,0x103 ; timer_create&lt;br /&gt;
    dec ebx&lt;br /&gt;
    push ebx&lt;br /&gt;
    push 1 ; SIGHUP&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov ax,0x104 ; timer_settime&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp $ ; loop forever&lt;br /&gt;
&lt;br /&gt;
callback:&lt;br /&gt;
    ; assume eax &amp;lt; 256, ebx = 0&lt;br /&gt;
    mov al,0x30 ; signal&lt;br /&gt;
    inc ebx&lt;br /&gt;
    mov ecx,callback&lt;br /&gt;
    int 0x80 ; (re)install signal handler&lt;br /&gt;
    ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Allocating memory ===&lt;br /&gt;
&lt;br /&gt;
On many Linux distros, the stack size is limited to 8MB by default. If this is not enough for your intro,&lt;br /&gt;
it is possible to increase this stack limit or to allocate memory in the data segment.&lt;br /&gt;
&lt;br /&gt;
To allocate space in the data segment, you can use the brk system call (0x2d).&lt;br /&gt;
This call takes in a memory address and attempts to set the value of the current ''program break'' to that address,&lt;br /&gt;
then returns the new address. The program break is the smallest memory address that is beyond the data segment.&lt;br /&gt;
By default, the data segment is zero bytes long.&lt;br /&gt;
Unfortunately, on modern systems, the default value of the program break is &lt;br /&gt;
randomized, so you can't just simply call brk with the amount of memory you want.&lt;br /&gt;
Instead, you have to call brk with an address of zero to get the current program break,&lt;br /&gt;
then add the amount of memory you want and call brk with the new address.&lt;br /&gt;
The following code does this in 15 bytes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    xchg eax,ebx&lt;br /&gt;
    add ebx,0x1000000 ; allocate 16MB&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    ; eax now contains the address of the program break, i.e.,&lt;br /&gt;
    ; you can use memory from eax-0x1000000 to eax-1 (inclusive)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To increase the stack size limit, you can use the setrlimit (0x4b) system call.&lt;br /&gt;
The following 11-byte snippet will remove the stack size limit completely.&lt;br /&gt;
Note that in some cases the user will not have permission to do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    dec ecx ; ecx = -1 aka set size to 'unlimited'&lt;br /&gt;
    push ecx&lt;br /&gt;
    push ecx&lt;br /&gt;
    mov bl,3 ; RLIMIT_STACK&lt;br /&gt;
    mov ecx,esp ; pointer to data for call&lt;br /&gt;
    mov al,0x4b ; setrlimit&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Self modifying code ===&lt;br /&gt;
With the tiny ELF header we've been using, the code segment is not writable, and unfortunately we need to sacrifice some bytes to make it so.&lt;br /&gt;
So, in many cases it's better to avoid using self modifying code. But, if you want to try it out, there are two ways to go about it.&lt;br /&gt;
In the ELF header, the p_flags field stores the access permissions of the code memory (1=execute, 2=write, 4=read).&lt;br /&gt;
In the tiny header, p_flags overlaps with e_phoff, and e_phoff (the offset of the program header from the beginning of the file) needs to be 4.&lt;br /&gt;
So, the only option for p_flags is read-only (turns out that the execute bit doesn't matter, and it will be executable anyways).&lt;br /&gt;
To make the code writable, we have to change p_flags to 7 (6 and 3 also accomplish the same thing because some are implied by others).&lt;br /&gt;
To do this we can either use a less overlapped header, or we can use the mprotect syscall to change&lt;br /&gt;
the permissions.&lt;br /&gt;
&lt;br /&gt;
See here for examples of some headers that allow you to change p_flags: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html&lt;br /&gt;
&lt;br /&gt;
The mprotect method is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov eax,0x7d ; mprotect&lt;br /&gt;
    mov ebx,$$ ; start address to change permissions for&lt;br /&gt;
    mov ecx,0x1000 ; number of bytes to change&lt;br /&gt;
    mov edx,7 ; new permissions&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Getting the screen size ===&lt;br /&gt;
&lt;br /&gt;
A lot of Linux intros have the screen resolution hard-coded, and some include many executables in the release, each for a different screen resolution. If you have enough space, you can easily get the screen resolution using the &amp;lt;tt&amp;gt;ioctl&amp;lt;/tt&amp;gt; syscall.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x36 ; ioctl&lt;br /&gt;
    mov ebx,0   ; ***PUT THE FILE DESCRIPTOR FOR /dev/fb0 HERE***&lt;br /&gt;
    xor ecx,ecx&lt;br /&gt;
    mov ch,0x46 ; FBIOGET_VSCREENINFO&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
    pop eax ; eax = horizontal resolution in pixels&lt;br /&gt;
    pop ebx ; ebx = vertical resolution in pixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For more information about what you can do with ioctl on the framebuffer, see here: https://www.kernel.org/doc/html/latest/fb/api.html&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=File_format&amp;diff=1009</id>
		<title>File format</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=File_format&amp;diff=1009"/>
				<updated>2022-02-10T16:41:15Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Linux */ add details of Linux ELF file format&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=File formats=&lt;br /&gt;
&lt;br /&gt;
File formats describe the content of a file. &lt;br /&gt;
&lt;br /&gt;
This page is not about:&lt;br /&gt;
* File systems which organize files on a partition&lt;br /&gt;
* Disk images which save a (disk) file system within one file&lt;br /&gt;
* Tape file formats, as they have a higher overhead usually&lt;br /&gt;
&lt;br /&gt;
==IBM PC==&lt;br /&gt;
&lt;br /&gt;
===COM===&lt;br /&gt;
System: MS-DOS&lt;br /&gt;
&lt;br /&gt;
Header: 0 bytes see [https://en.wikipedia.org/wiki/COM_file here]&lt;br /&gt;
&lt;br /&gt;
Native size unit: Bytes&lt;br /&gt;
&lt;br /&gt;
Loads to: 0100h&lt;br /&gt;
&lt;br /&gt;
Starts at: &lt;br /&gt;
&lt;br /&gt;
File extension: .com&lt;br /&gt;
&lt;br /&gt;
===EXE===&lt;br /&gt;
System: Windows&lt;br /&gt;
&lt;br /&gt;
Header: 200+&lt;br /&gt;
&lt;br /&gt;
Native size unit: Bytes&lt;br /&gt;
&lt;br /&gt;
Loads to: &lt;br /&gt;
&lt;br /&gt;
Starts at: &lt;br /&gt;
&lt;br /&gt;
File extension: .exe&lt;br /&gt;
&lt;br /&gt;
===ELF===&lt;br /&gt;
System: Linux&lt;br /&gt;
&lt;br /&gt;
Header: 45 - 100+&lt;br /&gt;
&lt;br /&gt;
Native size unit: Bytes&lt;br /&gt;
&lt;br /&gt;
Loads to: Random location (see [https://en.wikipedia.org/wiki/Address_space_layout_randomization#Linux here])&lt;br /&gt;
&lt;br /&gt;
Starts at: from 0x10000 to around 0x80000000 for 32bit binaries&lt;br /&gt;
&lt;br /&gt;
File extension: none&lt;br /&gt;
&lt;br /&gt;
==Atari ST==&lt;br /&gt;
===TOS===&lt;br /&gt;
System: Atari ST&lt;br /&gt;
&lt;br /&gt;
Header: 32 Bytes &lt;br /&gt;
&lt;br /&gt;
Native size unit: ???&lt;br /&gt;
&lt;br /&gt;
Loads to: &lt;br /&gt;
&lt;br /&gt;
Starts at:  &lt;br /&gt;
&lt;br /&gt;
File extension:  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Amiga==&lt;br /&gt;
===...===&lt;br /&gt;
System: Amiga&lt;br /&gt;
&lt;br /&gt;
Header: &lt;br /&gt;
&lt;br /&gt;
Native size unit: ???&lt;br /&gt;
&lt;br /&gt;
Loads to: &lt;br /&gt;
&lt;br /&gt;
Starts at:  &lt;br /&gt;
&lt;br /&gt;
File extension:  &lt;br /&gt;
&lt;br /&gt;
==Commodore 64==&lt;br /&gt;
===PRG===&lt;br /&gt;
System: CBM-DOS (Commodore, e.g. C64)&lt;br /&gt;
&lt;br /&gt;
Header: 2 bytes (= start address)&lt;br /&gt;
&lt;br /&gt;
Native size unit: Blocks (256 bytes including 2 bytes linking to next block)&lt;br /&gt;
&lt;br /&gt;
Loads to: given address in header&lt;br /&gt;
&lt;br /&gt;
Starts at: given address in header&lt;br /&gt;
&lt;br /&gt;
File extension: .prg&lt;br /&gt;
&lt;br /&gt;
===P00===&lt;br /&gt;
System: CBM-DOS / PC64 Emulator&lt;br /&gt;
&lt;br /&gt;
Header: extended 26 bytes; also includes the name; see [http://unusedino.de/ec64/technical/formats/pc64.html here]&lt;br /&gt;
&lt;br /&gt;
Native size unit: Blocks&lt;br /&gt;
&lt;br /&gt;
Loads to: given address in header&lt;br /&gt;
&lt;br /&gt;
Starts at: given address in header&lt;br /&gt;
&lt;br /&gt;
File extension: .p00&lt;br /&gt;
&lt;br /&gt;
==Atari 8bit==&lt;br /&gt;
===XEX, EXE, COM===&lt;br /&gt;
System: Atari&lt;br /&gt;
&lt;br /&gt;
Header: 6 bytes or more (FF FF &amp;lt;start address&amp;gt; &amp;lt;end address&amp;gt;); see also [https://www.atarimax.com/jindroush.atari.org/afmtexe.html here]&lt;br /&gt;
&lt;br /&gt;
Native size unit: ???&lt;br /&gt;
&lt;br /&gt;
Loads to: given start address in header&lt;br /&gt;
&lt;br /&gt;
Starts at: given end address in header&lt;br /&gt;
&lt;br /&gt;
File extension: .exe .com .xex (any ending possible)&lt;br /&gt;
&lt;br /&gt;
==Amstrad==&lt;br /&gt;
===BIN===&lt;br /&gt;
System: AMSDOS (Amstrad CPC)&lt;br /&gt;
&lt;br /&gt;
Header: 128 bytes (includes filename, start address, end address, etc.; 95 unused bytes; see also [https://www.cpcwiki.eu/index.php/AMSDOS_Header AMSDOS-Header]&lt;br /&gt;
&lt;br /&gt;
Native size unit: kb &lt;br /&gt;
&lt;br /&gt;
Loads to: given start address in header&lt;br /&gt;
&lt;br /&gt;
Starts at: given end address in header&lt;br /&gt;
&lt;br /&gt;
File extension: .bin (on PC)&lt;br /&gt;
&lt;br /&gt;
==Spectrum==&lt;br /&gt;
===Binary===&lt;br /&gt;
System: ZX Spectrum&lt;br /&gt;
&lt;br /&gt;
Header: none&lt;br /&gt;
&lt;br /&gt;
Native size unit: ???&lt;br /&gt;
&lt;br /&gt;
Loads to: special loader required; usually a BASIC program&lt;br /&gt;
&lt;br /&gt;
Starts at: see above&lt;br /&gt;
&lt;br /&gt;
File extension: ??? usually delivered within a disk image (.trd)&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=988</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=988"/>
				<updated>2021-12-27T21:48:45Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Getting something on screen */ Typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old XOR pattern:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method (method 1) is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method (method 2) uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers. Method 3, which saves some bytes over method 2 (especially when combined with visuals), is to use a shell based loader script.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pick apart the shell loader. Remember that in bash, $_ is the last argument passed to the previous command,&lt;br /&gt;
and $0 is the filename of the current executable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=shell&amp;gt;&lt;br /&gt;
cp $0 /tmp # copy the intro to /tmp&lt;br /&gt;
sed -i 1d $_/$0 # remove the first line from the copy with sed (aka remove the loader)&lt;br /&gt;
$_|aplay # execute the intro&lt;br /&gt;
rm $_ # remove the copy&lt;br /&gt;
exit # (so that the binary data which follows doesn't get executed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 10 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_&amp;lt;&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 or mmap directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Syncing audio with visuals is unfortunately not as easy as one would hope. Unlike many oldskool platforms, you can't just write audio and video data in your main loop and have everything work out nicely. The reason for this is that the audio is buffered with a relatively large buffer size, which is not easy to change. The effect of this is that audio writes will succeed instantly without blocking until about 1 second of audio has been written, and then the next write will block for about 1 second. This process then repeats. As you can imagine this means the visuals will run at about 1 FPS.&lt;br /&gt;
&lt;br /&gt;
Even if you know the exact audio buffer size, it doesn't really help to synchronize things because the synchronization will be dependent on the CPU speed (as well as how much CPU time background processes are taking, etc). In order to synchronize things properly you will need to use a timer. See the Limiting FPS section below for how to do this. You are looking at a cost of about 22 bytes for this timer at the very least.&lt;br /&gt;
&lt;br /&gt;
After you have a timer set up, you just need to decide on a target FPS and calculate how much audio you should write per frame. The general formula that you should write &amp;lt;tt&amp;gt;rate * channels * sample width in bytes / FPS&amp;lt;/tt&amp;gt; bytes per frame. For example, if your intro runs at 50 FPS and your audio uses 16bit samples in stereo at 8000Hz, then you should write &amp;lt;tt&amp;gt;8000*2*2/50 = 640&amp;lt;/tt&amp;gt; bytes of audio for every frame.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous Techniques ==&lt;br /&gt;
&lt;br /&gt;
=== Limiting FPS ===&lt;br /&gt;
&lt;br /&gt;
The framebuffer device /dev/fb0 will allow you to write to it as quickly as your CPU can manage,&lt;br /&gt;
so your intro can run at different speeds depending on the CPU speed. To correct this, you can use&lt;br /&gt;
a timer to limit FPS. Beyond limiting the frame rate, using a timer is seemingly necessary if you&lt;br /&gt;
want to have synchronized sound and graphics (but more research is needed).&lt;br /&gt;
&lt;br /&gt;
We will describe two approaches to setting up a timer. The first method uses the &amp;lt;tt&amp;gt;sys_timerfd_*&amp;lt;/tt&amp;gt;&lt;br /&gt;
syscalls, which creates a file descriptor where reads block until the timer expires.&lt;br /&gt;
The second uses the &amp;lt;tt&amp;gt;sys_timer_*&amp;lt;/tt&amp;gt; syscalls, which send signals that can be caught by installing a signal handler.&lt;br /&gt;
The first method is usually smaller.&lt;br /&gt;
&lt;br /&gt;
==== Method 1: timerfd ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assume this is placed at the beginning of the program (all registers zeroed)&lt;br /&gt;
    mov ax,0x142 ; timerfd_create&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov ax,0x145 ; timerfd_settime&lt;br /&gt;
    push ebx&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov bl,3 ; file descriptor of timer (returned by timerfd_create)&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    ; assume eax &amp;lt; 256, ebx = 3, edx &amp;gt;= 8&lt;br /&gt;
    mov al,3&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int 0x80 ; block until next frame&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Method 2: signal handler ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming this is at the beginning of the program (all registers zeroed)&lt;br /&gt;
    call callback ; set up signal handler initially&lt;br /&gt;
&lt;br /&gt;
    ; assume eax &amp;lt; 65536, ebx = 1&lt;br /&gt;
    mov ax,0x103 ; timer_create&lt;br /&gt;
    dec ebx&lt;br /&gt;
    push ebx&lt;br /&gt;
    push 1 ; SIGHUP&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov ax,0x104 ; timer_settime&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp $ ; loop forever&lt;br /&gt;
&lt;br /&gt;
callback:&lt;br /&gt;
    ; assume eax &amp;lt; 256, ebx = 0&lt;br /&gt;
    mov al,0x30 ; signal&lt;br /&gt;
    inc ebx&lt;br /&gt;
    mov ecx,callback&lt;br /&gt;
    int 0x80 ; (re)install signal handler&lt;br /&gt;
    ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Allocating memory ===&lt;br /&gt;
&lt;br /&gt;
On many Linux distros, the stack size is limited to 8MB by default. If this is not enough for your intro,&lt;br /&gt;
it is possible to increase this stack limit or to allocate memory in the data segment.&lt;br /&gt;
&lt;br /&gt;
To allocate space in the data segment, you can use the brk system call (0x2d).&lt;br /&gt;
This call takes in a memory address and attempts to set the value of the current ''program break'' to that address,&lt;br /&gt;
then returns the new address. The program break is the smallest memory address that is beyond the data segment.&lt;br /&gt;
By default, the data segment is zero bytes long.&lt;br /&gt;
Unfortunately, on modern systems, the default value of the program break is &lt;br /&gt;
randomized, so you can't just simply call brk with the amount of memory you want.&lt;br /&gt;
Instead, you have to call brk with an address of zero to get the current program break,&lt;br /&gt;
then add the amount of memory you want and call brk with the new address.&lt;br /&gt;
The following code does this in 15 bytes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    xchg eax,ebx&lt;br /&gt;
    add ebx,0x1000000 ; allocate 16MB&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    ; eax now contains the address of the program break, i.e.,&lt;br /&gt;
    ; you can use memory from eax-0x1000000 to eax-1 (inclusive)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To increase the stack size limit, you can use the setrlimit (0x4b) system call.&lt;br /&gt;
The following 11-byte snippet will remove the stack size limit completely.&lt;br /&gt;
Note that in some cases the user will not have permission to do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    dec ecx ; ecx = -1 aka set size to 'unlimited'&lt;br /&gt;
    push ecx&lt;br /&gt;
    push ecx&lt;br /&gt;
    mov bl,3 ; RLIMIT_STACK&lt;br /&gt;
    mov ecx,esp ; pointer to data for call&lt;br /&gt;
    mov al,0x4b ; setrlimit&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Self modifying code ===&lt;br /&gt;
With the tiny ELF header we've been using, the code segment is not writable, and unfortunately we need to sacrifice some bytes to make it so.&lt;br /&gt;
So, in many cases it's better to avoid using self modifying code. But, if you want to try it out, there are two ways to go about it.&lt;br /&gt;
In the ELF header, the p_flags field stores the access permissions of the code memory (1=execute, 2=write, 4=read).&lt;br /&gt;
In the tiny header, p_flags overlaps with e_phoff, and e_phoff (the offset of the program header from the beginning of the file) needs to be 4.&lt;br /&gt;
So, the only option for p_flags is read-only (turns out that the execute bit doesn't matter, and it will be executable anyways).&lt;br /&gt;
To make the code writable, we have to change p_flags to 7 (6 and 3 also accomplish the same thing because some are implied by others).&lt;br /&gt;
To do this we can either use a less overlapped header, or we can use the mprotect syscall to change&lt;br /&gt;
the permissions.&lt;br /&gt;
&lt;br /&gt;
See here for examples of some headers that allow you to change p_flags: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html&lt;br /&gt;
&lt;br /&gt;
The mprotect method is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov eax,0x7d ; mprotect&lt;br /&gt;
    mov ebx,$$ ; start address to change permissions for&lt;br /&gt;
    mov ecx,0x1000 ; number of bytes to change&lt;br /&gt;
    mov edx,7 ; new permissions&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Getting the screen size ===&lt;br /&gt;
&lt;br /&gt;
A lot of Linux intros have the screen resolution hard-coded, and some include many executables in the release, each for a different screen resolution. If you have enough space, you can easily get the screen resolution using the &amp;lt;tt&amp;gt;ioctl&amp;lt;/tt&amp;gt; syscall.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x36 ; ioctl&lt;br /&gt;
    mov ebx,0   ; ***PUT THE FILE DESCRIPTOR FOR /dev/fb0 HERE***&lt;br /&gt;
    xor ecx,ecx&lt;br /&gt;
    mov ch,0x46 ; FBIOGET_VSCREENINFO&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
    pop eax ; eax = horizontal resolution in pixels&lt;br /&gt;
    pop ebx ; ebx = vertical resolution in pixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For more information about what you can do with ioctl on the framebuffer, see here: https://www.kernel.org/doc/html/latest/fb/api.html&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=986</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=986"/>
				<updated>2021-12-27T21:36:18Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Syncing audio with visuals */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method (method 1) is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method (method 2) uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers. Method 3, which saves some bytes over method 2 (especially when combined with visuals), is to use a shell based loader script.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pick apart the shell loader. Remember that in bash, $_ is the last argument passed to the previous command,&lt;br /&gt;
and $0 is the filename of the current executable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=shell&amp;gt;&lt;br /&gt;
cp $0 /tmp # copy the intro to /tmp&lt;br /&gt;
sed -i 1d $_/$0 # remove the first line from the copy with sed (aka remove the loader)&lt;br /&gt;
$_|aplay # execute the intro&lt;br /&gt;
rm $_ # remove the copy&lt;br /&gt;
exit # (so that the binary data which follows doesn't get executed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 10 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_&amp;lt;&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 or mmap directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Syncing audio with visuals is unfortunately not as easy as one would hope. Unlike many oldskool platforms, you can't just write audio and video data in your main loop and have everything work out nicely. The reason for this is that the audio is buffered with a relatively large buffer size, which is not easy to change. The effect of this is that audio writes will succeed instantly without blocking until about 1 second of audio has been written, and then the next write will block for about 1 second. This process then repeats. As you can imagine this means the visuals will run at about 1 FPS.&lt;br /&gt;
&lt;br /&gt;
Even if you know the exact audio buffer size, it doesn't really help to synchronize things because the synchronization will be dependent on the CPU speed (as well as how much CPU time background processes are taking, etc). In order to synchronize things properly you will need to use a timer. See the Limiting FPS section below for how to do this. You are looking at a cost of about 22 bytes for this timer at the very least.&lt;br /&gt;
&lt;br /&gt;
After you have a timer set up, you just need to decide on a target FPS and calculate how much audio you should write per frame. The general formula that you should write &amp;lt;tt&amp;gt;rate * channels * sample width in bytes / FPS&amp;lt;/tt&amp;gt; bytes per frame. For example, if your intro runs at 50 FPS and your audio uses 16bit samples in stereo at 8000Hz, then you should write &amp;lt;tt&amp;gt;8000*2*2/50 = 640&amp;lt;/tt&amp;gt; bytes of audio for every frame.&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous Techniques ==&lt;br /&gt;
&lt;br /&gt;
=== Limiting FPS ===&lt;br /&gt;
&lt;br /&gt;
The framebuffer device /dev/fb0 will allow you to write to it as quickly as your CPU can manage,&lt;br /&gt;
so your intro can run at different speeds depending on the CPU speed. To correct this, you can use&lt;br /&gt;
a timer to limit FPS. Beyond limiting the frame rate, using a timer is seemingly necessary if you&lt;br /&gt;
want to have synchronized sound and graphics (but more research is needed).&lt;br /&gt;
&lt;br /&gt;
We will describe two approaches to setting up a timer. The first method uses the &amp;lt;tt&amp;gt;sys_timerfd_*&amp;lt;/tt&amp;gt;&lt;br /&gt;
syscalls, which creates a file descriptor where reads block until the timer expires.&lt;br /&gt;
The second uses the &amp;lt;tt&amp;gt;sys_timer_*&amp;lt;/tt&amp;gt; syscalls, which send signals that can be caught by installing a signal handler.&lt;br /&gt;
The first method is usually smaller.&lt;br /&gt;
&lt;br /&gt;
==== Method 1: timerfd ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assume this is placed at the beginning of the program (all registers zeroed)&lt;br /&gt;
    mov ax,0x142 ; timerfd_create&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov ax,0x145 ; timerfd_settime&lt;br /&gt;
    push ebx&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov bl,3 ; file descriptor of timer (returned by timerfd_create)&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    ; assume eax &amp;lt; 256, ebx = 3, edx &amp;gt;= 8&lt;br /&gt;
    mov al,3&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int 0x80 ; block until next frame&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Method 2: signal handler ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming this is at the beginning of the program (all registers zeroed)&lt;br /&gt;
    call callback ; set up signal handler initially&lt;br /&gt;
&lt;br /&gt;
    ; assume eax &amp;lt; 65536, ebx = 1&lt;br /&gt;
    mov ax,0x103 ; timer_create&lt;br /&gt;
    dec ebx&lt;br /&gt;
    push ebx&lt;br /&gt;
    push 1 ; SIGHUP&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov ax,0x104 ; timer_settime&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp $ ; loop forever&lt;br /&gt;
&lt;br /&gt;
callback:&lt;br /&gt;
    ; assume eax &amp;lt; 256, ebx = 0&lt;br /&gt;
    mov al,0x30 ; signal&lt;br /&gt;
    inc ebx&lt;br /&gt;
    mov ecx,callback&lt;br /&gt;
    int 0x80 ; (re)install signal handler&lt;br /&gt;
    ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Allocating memory ===&lt;br /&gt;
&lt;br /&gt;
On many Linux distros, the stack size is limited to 8MB by default. If this is not enough for your intro,&lt;br /&gt;
it is possible to increase this stack limit or to allocate memory in the data segment.&lt;br /&gt;
&lt;br /&gt;
To allocate space in the data segment, you can use the brk system call (0x2d).&lt;br /&gt;
This call takes in a memory address and attempts to set the value of the current ''program break'' to that address,&lt;br /&gt;
then returns the new address. The program break is the smallest memory address that is beyond the data segment.&lt;br /&gt;
By default, the data segment is zero bytes long.&lt;br /&gt;
Unfortunately, on modern systems, the default value of the program break is &lt;br /&gt;
randomized, so you can't just simply call brk with the amount of memory you want.&lt;br /&gt;
Instead, you have to call brk with an address of zero to get the current program break,&lt;br /&gt;
then add the amount of memory you want and call brk with the new address.&lt;br /&gt;
The following code does this in 15 bytes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    xchg eax,ebx&lt;br /&gt;
    add ebx,0x1000000 ; allocate 16MB&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    ; eax now contains the address of the program break, i.e.,&lt;br /&gt;
    ; you can use memory from eax-0x1000000 to eax-1 (inclusive)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To increase the stack size limit, you can use the setrlimit (0x4b) system call.&lt;br /&gt;
The following 11-byte snippet will remove the stack size limit completely.&lt;br /&gt;
Note that in some cases the user will not have permission to do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    dec ecx ; ecx = -1 aka set size to 'unlimited'&lt;br /&gt;
    push ecx&lt;br /&gt;
    push ecx&lt;br /&gt;
    mov bl,3 ; RLIMIT_STACK&lt;br /&gt;
    mov ecx,esp ; pointer to data for call&lt;br /&gt;
    mov al,0x4b ; setrlimit&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Self modifying code ===&lt;br /&gt;
With the tiny ELF header we've been using, the code segment is not writable, and unfortunately we need to sacrifice some bytes to make it so.&lt;br /&gt;
So, in many cases it's better to avoid using self modifying code. But, if you want to try it out, there are two ways to go about it.&lt;br /&gt;
In the ELF header, the p_flags field stores the access permissions of the code memory (1=execute, 2=write, 4=read).&lt;br /&gt;
In the tiny header, p_flags overlaps with e_phoff, and e_phoff (the offset of the program header from the beginning of the file) needs to be 4.&lt;br /&gt;
So, the only option for p_flags is read-only (turns out that the execute bit doesn't matter, and it will be executable anyways).&lt;br /&gt;
To make the code writable, we have to change p_flags to 7 (6 and 3 also accomplish the same thing because some are implied by others).&lt;br /&gt;
To do this we can either use a less overlapped header, or we can use the mprotect syscall to change&lt;br /&gt;
the permissions.&lt;br /&gt;
&lt;br /&gt;
See here for examples of some headers that allow you to change p_flags: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html&lt;br /&gt;
&lt;br /&gt;
The mprotect method is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov eax,0x7d ; mprotect&lt;br /&gt;
    mov ebx,$$ ; start address to change permissions for&lt;br /&gt;
    mov ecx,0x1000 ; number of bytes to change&lt;br /&gt;
    mov edx,7 ; new permissions&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Getting the screen size ===&lt;br /&gt;
&lt;br /&gt;
A lot of Linux intros have the screen resolution hard-coded, and some include many executables in the release, each for a different screen resolution. If you have enough space, you can easily get the screen resolution using the &amp;lt;tt&amp;gt;ioctl&amp;lt;/tt&amp;gt; syscall.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x36 ; ioctl&lt;br /&gt;
    mov ebx,0   ; ***PUT THE FILE DESCRIPTOR FOR /dev/fb0 HERE***&lt;br /&gt;
    xor ecx,ecx&lt;br /&gt;
    mov ch,0x46 ; FBIOGET_VSCREENINFO&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
    pop eax ; eax = horizontal resolution in pixels&lt;br /&gt;
    pop ebx ; ebx = vertical resolution in pixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For more information about what you can do with ioctl on the framebuffer, see here: https://www.kernel.org/doc/html/latest/fb/api.html&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=985</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=985"/>
				<updated>2021-12-27T21:14:32Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Getting the screen size */ Fix typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method (method 1) is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method (method 2) uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers. Method 3, which saves some bytes over method 2 (especially when combined with visuals), is to use a shell based loader script.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pick apart the shell loader. Remember that in bash, $_ is the last argument passed to the previous command,&lt;br /&gt;
and $0 is the filename of the current executable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=shell&amp;gt;&lt;br /&gt;
cp $0 /tmp # copy the intro to /tmp&lt;br /&gt;
sed -i 1d $_/$0 # remove the first line from the copy with sed (aka remove the loader)&lt;br /&gt;
$_|aplay # execute the intro&lt;br /&gt;
rm $_ # remove the copy&lt;br /&gt;
exit # (so that the binary data which follows doesn't get executed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 10 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_&amp;lt;&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 or mmap directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous Techniques ==&lt;br /&gt;
&lt;br /&gt;
=== Limiting FPS ===&lt;br /&gt;
&lt;br /&gt;
The framebuffer device /dev/fb0 will allow you to write to it as quickly as your CPU can manage,&lt;br /&gt;
so your intro can run at different speeds depending on the CPU speed. To correct this, you can use&lt;br /&gt;
a timer to limit FPS. Beyond limiting the frame rate, using a timer is seemingly necessary if you&lt;br /&gt;
want to have synchronized sound and graphics (but more research is needed).&lt;br /&gt;
&lt;br /&gt;
We will describe two approaches to setting up a timer. The first method uses the &amp;lt;tt&amp;gt;sys_timerfd_*&amp;lt;/tt&amp;gt;&lt;br /&gt;
syscalls, which creates a file descriptor where reads block until the timer expires.&lt;br /&gt;
The second uses the &amp;lt;tt&amp;gt;sys_timer_*&amp;lt;/tt&amp;gt; syscalls, which send signals that can be caught by installing a signal handler.&lt;br /&gt;
The first method is usually smaller.&lt;br /&gt;
&lt;br /&gt;
==== Method 1: timerfd ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assume this is placed at the beginning of the program (all registers zeroed)&lt;br /&gt;
    mov ax,0x142 ; timerfd_create&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov ax,0x145 ; timerfd_settime&lt;br /&gt;
    push ebx&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov bl,3 ; file descriptor of timer (returned by timerfd_create)&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    ; assume eax &amp;lt; 256, ebx = 3, edx &amp;gt;= 8&lt;br /&gt;
    mov al,3&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int 0x80 ; block until next frame&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Method 2: signal handler ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming this is at the beginning of the program (all registers zeroed)&lt;br /&gt;
    call callback ; set up signal handler initially&lt;br /&gt;
&lt;br /&gt;
    ; assume eax &amp;lt; 65536, ebx = 1&lt;br /&gt;
    mov ax,0x103 ; timer_create&lt;br /&gt;
    dec ebx&lt;br /&gt;
    push ebx&lt;br /&gt;
    push 1 ; SIGHUP&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov ax,0x104 ; timer_settime&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp $ ; loop forever&lt;br /&gt;
&lt;br /&gt;
callback:&lt;br /&gt;
    ; assume eax &amp;lt; 256, ebx = 0&lt;br /&gt;
    mov al,0x30 ; signal&lt;br /&gt;
    inc ebx&lt;br /&gt;
    mov ecx,callback&lt;br /&gt;
    int 0x80 ; (re)install signal handler&lt;br /&gt;
    ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Allocating memory ===&lt;br /&gt;
&lt;br /&gt;
On many Linux distros, the stack size is limited to 8MB by default. If this is not enough for your intro,&lt;br /&gt;
it is possible to increase this stack limit or to allocate memory in the data segment.&lt;br /&gt;
&lt;br /&gt;
To allocate space in the data segment, you can use the brk system call (0x2d).&lt;br /&gt;
This call takes in a memory address and attempts to set the value of the current ''program break'' to that address,&lt;br /&gt;
then returns the new address. The program break is the smallest memory address that is beyond the data segment.&lt;br /&gt;
By default, the data segment is zero bytes long.&lt;br /&gt;
Unfortunately, on modern systems, the default value of the program break is &lt;br /&gt;
randomized, so you can't just simply call brk with the amount of memory you want.&lt;br /&gt;
Instead, you have to call brk with an address of zero to get the current program break,&lt;br /&gt;
then add the amount of memory you want and call brk with the new address.&lt;br /&gt;
The following code does this in 15 bytes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    xchg eax,ebx&lt;br /&gt;
    add ebx,0x1000000 ; allocate 16MB&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    ; eax now contains the address of the program break, i.e.,&lt;br /&gt;
    ; you can use memory from eax-0x1000000 to eax-1 (inclusive)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To increase the stack size limit, you can use the setrlimit (0x4b) system call.&lt;br /&gt;
The following 11-byte snippet will remove the stack size limit completely.&lt;br /&gt;
Note that in some cases the user will not have permission to do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    dec ecx ; ecx = -1 aka set size to 'unlimited'&lt;br /&gt;
    push ecx&lt;br /&gt;
    push ecx&lt;br /&gt;
    mov bl,3 ; RLIMIT_STACK&lt;br /&gt;
    mov ecx,esp ; pointer to data for call&lt;br /&gt;
    mov al,0x4b ; setrlimit&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Self modifying code ===&lt;br /&gt;
With the tiny ELF header we've been using, the code segment is not writable, and unfortunately we need to sacrifice some bytes to make it so.&lt;br /&gt;
So, in many cases it's better to avoid using self modifying code. But, if you want to try it out, there are two ways to go about it.&lt;br /&gt;
In the ELF header, the p_flags field stores the access permissions of the code memory (1=execute, 2=write, 4=read).&lt;br /&gt;
In the tiny header, p_flags overlaps with e_phoff, and e_phoff (the offset of the program header from the beginning of the file) needs to be 4.&lt;br /&gt;
So, the only option for p_flags is read-only (turns out that the execute bit doesn't matter, and it will be executable anyways).&lt;br /&gt;
To make the code writable, we have to change p_flags to 7 (6 and 3 also accomplish the same thing because some are implied by others).&lt;br /&gt;
To do this we can either use a less overlapped header, or we can use the mprotect syscall to change&lt;br /&gt;
the permissions.&lt;br /&gt;
&lt;br /&gt;
See here for examples of some headers that allow you to change p_flags: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html&lt;br /&gt;
&lt;br /&gt;
The mprotect method is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov eax,0x7d ; mprotect&lt;br /&gt;
    mov ebx,$$ ; start address to change permissions for&lt;br /&gt;
    mov ecx,0x1000 ; number of bytes to change&lt;br /&gt;
    mov edx,7 ; new permissions&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Getting the screen size ===&lt;br /&gt;
&lt;br /&gt;
A lot of Linux intros have the screen resolution hard-coded, and some include many executables in the release, each for a different screen resolution. If you have enough space, you can easily get the screen resolution using the &amp;lt;tt&amp;gt;ioctl&amp;lt;/tt&amp;gt; syscall.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x36 ; ioctl&lt;br /&gt;
    mov ebx,0   ; ***PUT THE FILE DESCRIPTOR FOR /dev/fb0 HERE***&lt;br /&gt;
    xor ecx,ecx&lt;br /&gt;
    mov ch,0x46 ; FBIOGET_VSCREENINFO&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
    pop eax ; eax = horizontal resolution in pixels&lt;br /&gt;
    pop ebx ; ebx = vertical resolution in pixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For more information about what you can do with ioctl on the framebuffer, see here: https://www.kernel.org/doc/html/latest/fb/api.html&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=984</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=984"/>
				<updated>2021-12-27T21:11:57Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: Add code for getting the screen resolution&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method (method 1) is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method (method 2) uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers. Method 3, which saves some bytes over method 2 (especially when combined with visuals), is to use a shell based loader script.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pick apart the shell loader. Remember that in bash, $_ is the last argument passed to the previous command,&lt;br /&gt;
and $0 is the filename of the current executable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=shell&amp;gt;&lt;br /&gt;
cp $0 /tmp # copy the intro to /tmp&lt;br /&gt;
sed -i 1d $_/$0 # remove the first line from the copy with sed (aka remove the loader)&lt;br /&gt;
$_|aplay # execute the intro&lt;br /&gt;
rm $_ # remove the copy&lt;br /&gt;
exit # (so that the binary data which follows doesn't get executed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 10 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_&amp;lt;&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 or mmap directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous Techniques ==&lt;br /&gt;
&lt;br /&gt;
=== Limiting FPS ===&lt;br /&gt;
&lt;br /&gt;
The framebuffer device /dev/fb0 will allow you to write to it as quickly as your CPU can manage,&lt;br /&gt;
so your intro can run at different speeds depending on the CPU speed. To correct this, you can use&lt;br /&gt;
a timer to limit FPS. Beyond limiting the frame rate, using a timer is seemingly necessary if you&lt;br /&gt;
want to have synchronized sound and graphics (but more research is needed).&lt;br /&gt;
&lt;br /&gt;
We will describe two approaches to setting up a timer. The first method uses the &amp;lt;tt&amp;gt;sys_timerfd_*&amp;lt;/tt&amp;gt;&lt;br /&gt;
syscalls, which creates a file descriptor where reads block until the timer expires.&lt;br /&gt;
The second uses the &amp;lt;tt&amp;gt;sys_timer_*&amp;lt;/tt&amp;gt; syscalls, which send signals that can be caught by installing a signal handler.&lt;br /&gt;
The first method is usually smaller.&lt;br /&gt;
&lt;br /&gt;
==== Method 1: timerfd ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assume this is placed at the beginning of the program (all registers zeroed)&lt;br /&gt;
    mov ax,0x142 ; timerfd_create&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov ax,0x145 ; timerfd_settime&lt;br /&gt;
    push ebx&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov bl,3 ; file descriptor of timer (returned by timerfd_create)&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    ; assume eax &amp;lt; 256, ebx = 3, edx &amp;gt;= 8&lt;br /&gt;
    mov al,3&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int 0x80 ; block until next frame&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Method 2: signal handler ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming this is at the beginning of the program (all registers zeroed)&lt;br /&gt;
    call callback ; set up signal handler initially&lt;br /&gt;
&lt;br /&gt;
    ; assume eax &amp;lt; 65536, ebx = 1&lt;br /&gt;
    mov ax,0x103 ; timer_create&lt;br /&gt;
    dec ebx&lt;br /&gt;
    push ebx&lt;br /&gt;
    push 1 ; SIGHUP&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov ax,0x104 ; timer_settime&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp $ ; loop forever&lt;br /&gt;
&lt;br /&gt;
callback:&lt;br /&gt;
    ; assume eax &amp;lt; 256, ebx = 0&lt;br /&gt;
    mov al,0x30 ; signal&lt;br /&gt;
    inc ebx&lt;br /&gt;
    mov ecx,callback&lt;br /&gt;
    int 0x80 ; (re)install signal handler&lt;br /&gt;
    ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Allocating memory ===&lt;br /&gt;
&lt;br /&gt;
On many Linux distros, the stack size is limited to 8MB by default. If this is not enough for your intro,&lt;br /&gt;
it is possible to increase this stack limit or to allocate memory in the data segment.&lt;br /&gt;
&lt;br /&gt;
To allocate space in the data segment, you can use the brk system call (0x2d).&lt;br /&gt;
This call takes in a memory address and attempts to set the value of the current ''program break'' to that address,&lt;br /&gt;
then returns the new address. The program break is the smallest memory address that is beyond the data segment.&lt;br /&gt;
By default, the data segment is zero bytes long.&lt;br /&gt;
Unfortunately, on modern systems, the default value of the program break is &lt;br /&gt;
randomized, so you can't just simply call brk with the amount of memory you want.&lt;br /&gt;
Instead, you have to call brk with an address of zero to get the current program break,&lt;br /&gt;
then add the amount of memory you want and call brk with the new address.&lt;br /&gt;
The following code does this in 15 bytes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    xchg eax,ebx&lt;br /&gt;
    add ebx,0x1000000 ; allocate 16MB&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    ; eax now contains the address of the program break, i.e.,&lt;br /&gt;
    ; you can use memory from eax-0x1000000 to eax-1 (inclusive)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To increase the stack size limit, you can use the setrlimit (0x4b) system call.&lt;br /&gt;
The following 11-byte snippet will remove the stack size limit completely.&lt;br /&gt;
Note that in some cases the user will not have permission to do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    dec ecx ; ecx = -1 aka set size to 'unlimited'&lt;br /&gt;
    push ecx&lt;br /&gt;
    push ecx&lt;br /&gt;
    mov bl,3 ; RLIMIT_STACK&lt;br /&gt;
    mov ecx,esp ; pointer to data for call&lt;br /&gt;
    mov al,0x4b ; setrlimit&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Self modifying code ===&lt;br /&gt;
With the tiny ELF header we've been using, the code segment is not writable, and unfortunately we need to sacrifice some bytes to make it so.&lt;br /&gt;
So, in many cases it's better to avoid using self modifying code. But, if you want to try it out, there are two ways to go about it.&lt;br /&gt;
In the ELF header, the p_flags field stores the access permissions of the code memory (1=execute, 2=write, 4=read).&lt;br /&gt;
In the tiny header, p_flags overlaps with e_phoff, and e_phoff (the offset of the program header from the beginning of the file) needs to be 4.&lt;br /&gt;
So, the only option for p_flags is read-only (turns out that the execute bit doesn't matter, and it will be executable anyways).&lt;br /&gt;
To make the code writable, we have to change p_flags to 7 (6 and 3 also accomplish the same thing because some are implied by others).&lt;br /&gt;
To do this we can either use a less overlapped header, or we can use the mprotect syscall to change&lt;br /&gt;
the permissions.&lt;br /&gt;
&lt;br /&gt;
See here for examples of some headers that allow you to change p_flags: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html&lt;br /&gt;
&lt;br /&gt;
The mprotect method is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov eax,0x7d ; mprotect&lt;br /&gt;
    mov ebx,$$ ; start address to change permissions for&lt;br /&gt;
    mov ecx,0x1000 ; number of bytes to change&lt;br /&gt;
    mov edx,7 ; new permissions&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Getting the screen size ===&lt;br /&gt;
&lt;br /&gt;
A lot of Linux intros have the screen resolution hard-coded, and some include many executables in the release, each for a different screen resolution. If you have enough space, you can easily get the screen resolution using the &amp;lt;tt&amp;gt;ioctl&amp;lt;/tt&amp;gt; syscall.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x36 ; ioctl&lt;br /&gt;
    mov ebx,0   ; ***PUT THE FILE DESCRIPTOR FOR /dev/fb0 HERE***&lt;br /&gt;
    xor ecx,ecx&lt;br /&gt;
    mov ch,0x46 ; FBIOGET_FSCREENINFO&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
    pop eax ; eax = horizontal resolution in pixels&lt;br /&gt;
    pop ebx ; ebx = vertical resolution in pixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For more information about what you can do with ioctl on the framebuffer, see here: https://www.kernel.org/doc/html/latest/fb/api.html&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=973</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=973"/>
				<updated>2021-12-04T02:28:46Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Combining audio and video */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method (method 1) is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method (method 2) uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers. Method 3, which saves some bytes over method 2 (especially when combined with visuals), is to use a shell based loader script.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pick apart the shell loader. Remember that in bash, $_ is the last argument passed to the previous command,&lt;br /&gt;
and $0 is the filename of the current executable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=shell&amp;gt;&lt;br /&gt;
cp $0 /tmp # copy the intro to /tmp&lt;br /&gt;
sed -i 1d $_/$0 # remove the first line from the copy with sed (aka remove the loader)&lt;br /&gt;
$_|aplay # execute the intro&lt;br /&gt;
rm $_ # remove the copy&lt;br /&gt;
exit # (so that the binary data which follows doesn't get executed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 10 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_&amp;lt;&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 or mmap directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous Techniques ==&lt;br /&gt;
&lt;br /&gt;
=== Limiting FPS ===&lt;br /&gt;
&lt;br /&gt;
The framebuffer device /dev/fb0 will allow you to write to it as quickly as your CPU can manage,&lt;br /&gt;
so your intro can run at different speeds depending on the CPU speed. To correct this, you can use&lt;br /&gt;
a timer to limit FPS. Beyond limiting the frame rate, using a timer is seemingly necessary if you&lt;br /&gt;
want to have synchronized sound and graphics (but more research is needed).&lt;br /&gt;
&lt;br /&gt;
We will describe two approaches to setting up a timer. The first method uses the &amp;lt;tt&amp;gt;sys_timerfd_*&amp;lt;/tt&amp;gt;&lt;br /&gt;
syscalls, which creates a file descriptor where reads block until the timer expires.&lt;br /&gt;
The second uses the &amp;lt;tt&amp;gt;sys_timer_*&amp;lt;/tt&amp;gt; syscalls, which send signals that can be caught by installing a signal handler.&lt;br /&gt;
The first method is usually smaller.&lt;br /&gt;
&lt;br /&gt;
==== Method 1: timerfd ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assume this is placed at the beginning of the program (all registers zeroed)&lt;br /&gt;
    mov ax,0x142 ; timerfd_create&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov ax,0x145 ; timerfd_settime&lt;br /&gt;
    push ebx&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov bl,3 ; file descriptor of timer (returned by timerfd_create)&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    ; assume eax &amp;lt; 256, ebx = 3, edx &amp;gt;= 8&lt;br /&gt;
    mov al,3&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int 0x80 ; block until next frame&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Method 2: signal handler ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming this is at the beginning of the program (all registers zeroed)&lt;br /&gt;
    call callback ; set up signal handler initially&lt;br /&gt;
&lt;br /&gt;
    ; assume eax &amp;lt; 65536, ebx = 1&lt;br /&gt;
    mov ax,0x103 ; timer_create&lt;br /&gt;
    dec ebx&lt;br /&gt;
    push ebx&lt;br /&gt;
    push 1 ; SIGHUP&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov ax,0x104 ; timer_settime&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp $ ; loop forever&lt;br /&gt;
&lt;br /&gt;
callback:&lt;br /&gt;
    ; assume eax &amp;lt; 256, ebx = 0&lt;br /&gt;
    mov al,0x30 ; signal&lt;br /&gt;
    inc ebx&lt;br /&gt;
    mov ecx,callback&lt;br /&gt;
    int 0x80 ; (re)install signal handler&lt;br /&gt;
    ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Allocating memory ===&lt;br /&gt;
&lt;br /&gt;
On many Linux distros, the stack size is limited to 8MB by default. If this is not enough for your intro,&lt;br /&gt;
it is possible to increase this stack limit or to allocate memory in the data segment.&lt;br /&gt;
&lt;br /&gt;
To allocate space in the data segment, you can use the brk system call (0x2d).&lt;br /&gt;
This call takes in a memory address and attempts to set the value of the current ''program break'' to that address,&lt;br /&gt;
then returns the new address. The program break is the smallest memory address that is beyond the data segment.&lt;br /&gt;
By default, the data segment is zero bytes long.&lt;br /&gt;
Unfortunately, on modern systems, the default value of the program break is &lt;br /&gt;
randomized, so you can't just simply call brk with the amount of memory you want.&lt;br /&gt;
Instead, you have to call brk with an address of zero to get the current program break,&lt;br /&gt;
then add the amount of memory you want and call brk with the new address.&lt;br /&gt;
The following code does this in 15 bytes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    xchg eax,ebx&lt;br /&gt;
    add ebx,0x1000000 ; allocate 16MB&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    ; eax now contains the address of the program break, i.e.,&lt;br /&gt;
    ; you can use memory from eax-0x1000000 to eax-1 (inclusive)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To increase the stack size limit, you can use the setrlimit (0x4b) system call.&lt;br /&gt;
The following 11-byte snippet will remove the stack size limit completely.&lt;br /&gt;
Note that in some cases the user will not have permission to do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    dec ecx ; ecx = -1 aka set size to 'unlimited'&lt;br /&gt;
    push ecx&lt;br /&gt;
    push ecx&lt;br /&gt;
    mov bl,3 ; RLIMIT_STACK&lt;br /&gt;
    mov ecx,esp ; pointer to data for call&lt;br /&gt;
    mov al,0x4b ; setrlimit&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Self modifying code ===&lt;br /&gt;
With the tiny ELF header we've been using, the code segment is not writable, and unfortunately we need to sacrifice some bytes to make it so.&lt;br /&gt;
So, in many cases it's better to avoid using self modifying code. But, if you want to try it out, there are two ways to go about it.&lt;br /&gt;
In the ELF header, the p_flags field stores the access permissions of the code memory (1=execute, 2=write, 4=read).&lt;br /&gt;
In the tiny header, p_flags overlaps with e_phoff, and e_phoff (the offset of the program header from the beginning of the file) needs to be 4.&lt;br /&gt;
So, the only option for p_flags is read-only (turns out that the execute bit doesn't matter, and it will be executable anyways).&lt;br /&gt;
To make the code writable, we have to change p_flags to 7 (6 and 3 also accomplish the same thing because some are implied by others).&lt;br /&gt;
To do this we can either use a less overlapped header, or we can use the mprotect syscall to change&lt;br /&gt;
the permissions.&lt;br /&gt;
&lt;br /&gt;
See here for examples of some headers that allow you to change p_flags: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html&lt;br /&gt;
&lt;br /&gt;
The mprotect method is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov eax,0x7d ; mprotect&lt;br /&gt;
    mov ebx,$$ ; start address to change permissions for&lt;br /&gt;
    mov ecx,0x1000 ; number of bytes to change&lt;br /&gt;
    mov edx,7 ; new permissions&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=972</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=972"/>
				<updated>2021-12-04T02:28:04Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Method 3: shell loader */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method (method 1) is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method (method 2) uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers. Method 3, which saves some bytes over method 2 (especially when combined with visuals), is to use a shell based loader script.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pick apart the shell loader. Remember that in bash, $_ is the last argument passed to the previous command,&lt;br /&gt;
and $0 is the filename of the current executable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=shell&amp;gt;&lt;br /&gt;
cp $0 /tmp # copy the intro to /tmp&lt;br /&gt;
sed -i 1d $_/$0 # remove the first line from the copy with sed (aka remove the loader)&lt;br /&gt;
$_|aplay # execute the intro&lt;br /&gt;
rm $_ # remove the copy&lt;br /&gt;
exit # (so that the binary data which follows doesn't get executed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 11 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_&amp;lt;&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 or mmap directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous Techniques ==&lt;br /&gt;
&lt;br /&gt;
=== Limiting FPS ===&lt;br /&gt;
&lt;br /&gt;
The framebuffer device /dev/fb0 will allow you to write to it as quickly as your CPU can manage,&lt;br /&gt;
so your intro can run at different speeds depending on the CPU speed. To correct this, you can use&lt;br /&gt;
a timer to limit FPS. Beyond limiting the frame rate, using a timer is seemingly necessary if you&lt;br /&gt;
want to have synchronized sound and graphics (but more research is needed).&lt;br /&gt;
&lt;br /&gt;
We will describe two approaches to setting up a timer. The first method uses the &amp;lt;tt&amp;gt;sys_timerfd_*&amp;lt;/tt&amp;gt;&lt;br /&gt;
syscalls, which creates a file descriptor where reads block until the timer expires.&lt;br /&gt;
The second uses the &amp;lt;tt&amp;gt;sys_timer_*&amp;lt;/tt&amp;gt; syscalls, which send signals that can be caught by installing a signal handler.&lt;br /&gt;
The first method is usually smaller.&lt;br /&gt;
&lt;br /&gt;
==== Method 1: timerfd ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assume this is placed at the beginning of the program (all registers zeroed)&lt;br /&gt;
    mov ax,0x142 ; timerfd_create&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov ax,0x145 ; timerfd_settime&lt;br /&gt;
    push ebx&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov bl,3 ; file descriptor of timer (returned by timerfd_create)&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    ; assume eax &amp;lt; 256, ebx = 3, edx &amp;gt;= 8&lt;br /&gt;
    mov al,3&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int 0x80 ; block until next frame&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Method 2: signal handler ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming this is at the beginning of the program (all registers zeroed)&lt;br /&gt;
    call callback ; set up signal handler initially&lt;br /&gt;
&lt;br /&gt;
    ; assume eax &amp;lt; 65536, ebx = 1&lt;br /&gt;
    mov ax,0x103 ; timer_create&lt;br /&gt;
    dec ebx&lt;br /&gt;
    push ebx&lt;br /&gt;
    push 1 ; SIGHUP&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov ax,0x104 ; timer_settime&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp $ ; loop forever&lt;br /&gt;
&lt;br /&gt;
callback:&lt;br /&gt;
    ; assume eax &amp;lt; 256, ebx = 0&lt;br /&gt;
    mov al,0x30 ; signal&lt;br /&gt;
    inc ebx&lt;br /&gt;
    mov ecx,callback&lt;br /&gt;
    int 0x80 ; (re)install signal handler&lt;br /&gt;
    ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Allocating memory ===&lt;br /&gt;
&lt;br /&gt;
On many Linux distros, the stack size is limited to 8MB by default. If this is not enough for your intro,&lt;br /&gt;
it is possible to increase this stack limit or to allocate memory in the data segment.&lt;br /&gt;
&lt;br /&gt;
To allocate space in the data segment, you can use the brk system call (0x2d).&lt;br /&gt;
This call takes in a memory address and attempts to set the value of the current ''program break'' to that address,&lt;br /&gt;
then returns the new address. The program break is the smallest memory address that is beyond the data segment.&lt;br /&gt;
By default, the data segment is zero bytes long.&lt;br /&gt;
Unfortunately, on modern systems, the default value of the program break is &lt;br /&gt;
randomized, so you can't just simply call brk with the amount of memory you want.&lt;br /&gt;
Instead, you have to call brk with an address of zero to get the current program break,&lt;br /&gt;
then add the amount of memory you want and call brk with the new address.&lt;br /&gt;
The following code does this in 15 bytes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    xchg eax,ebx&lt;br /&gt;
    add ebx,0x1000000 ; allocate 16MB&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    ; eax now contains the address of the program break, i.e.,&lt;br /&gt;
    ; you can use memory from eax-0x1000000 to eax-1 (inclusive)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To increase the stack size limit, you can use the setrlimit (0x4b) system call.&lt;br /&gt;
The following 11-byte snippet will remove the stack size limit completely.&lt;br /&gt;
Note that in some cases the user will not have permission to do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    dec ecx ; ecx = -1 aka set size to 'unlimited'&lt;br /&gt;
    push ecx&lt;br /&gt;
    push ecx&lt;br /&gt;
    mov bl,3 ; RLIMIT_STACK&lt;br /&gt;
    mov ecx,esp ; pointer to data for call&lt;br /&gt;
    mov al,0x4b ; setrlimit&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Self modifying code ===&lt;br /&gt;
With the tiny ELF header we've been using, the code segment is not writable, and unfortunately we need to sacrifice some bytes to make it so.&lt;br /&gt;
So, in many cases it's better to avoid using self modifying code. But, if you want to try it out, there are two ways to go about it.&lt;br /&gt;
In the ELF header, the p_flags field stores the access permissions of the code memory (1=execute, 2=write, 4=read).&lt;br /&gt;
In the tiny header, p_flags overlaps with e_phoff, and e_phoff (the offset of the program header from the beginning of the file) needs to be 4.&lt;br /&gt;
So, the only option for p_flags is read-only (turns out that the execute bit doesn't matter, and it will be executable anyways).&lt;br /&gt;
To make the code writable, we have to change p_flags to 7 (6 and 3 also accomplish the same thing because some are implied by others).&lt;br /&gt;
To do this we can either use a less overlapped header, or we can use the mprotect syscall to change&lt;br /&gt;
the permissions.&lt;br /&gt;
&lt;br /&gt;
See here for examples of some headers that allow you to change p_flags: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html&lt;br /&gt;
&lt;br /&gt;
The mprotect method is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov eax,0x7d ; mprotect&lt;br /&gt;
    mov ebx,$$ ; start address to change permissions for&lt;br /&gt;
    mov ecx,0x1000 ; number of bytes to change&lt;br /&gt;
    mov edx,7 ; new permissions&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=971</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=971"/>
				<updated>2021-12-03T23:35:27Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Miscellaneous Techniques */ add self modifying code section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method (method 1) is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method (method 2) uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers. Method 3, which saves some bytes over method 2 (especially when combined with visuals), is to use a shell based loader script.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pick apart the shell loader. Remember that in bash, $_ is the last argument passed to the previous command,&lt;br /&gt;
and $0 is the filename of the current executable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=shell&amp;gt;&lt;br /&gt;
cp $0 /tmp # copy the intro to /tmp&lt;br /&gt;
sed -i 1d $_/$0 # remove the first line from the copy with sed (aka remove the loader)&lt;br /&gt;
$_|aplay # execute the intro&lt;br /&gt;
rm $_ # remove the copy&lt;br /&gt;
exit # (so that the binary data which follows doesn't get executed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 11 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_ 0&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous Techniques ==&lt;br /&gt;
&lt;br /&gt;
=== Limiting FPS ===&lt;br /&gt;
&lt;br /&gt;
The framebuffer device /dev/fb0 will allow you to write to it as quickly as your CPU can manage,&lt;br /&gt;
so your intro can run at different speeds depending on the CPU speed. To correct this, you can use&lt;br /&gt;
a timer to limit FPS. Beyond limiting the frame rate, using a timer is seemingly necessary if you&lt;br /&gt;
want to have synchronized sound and graphics (but more research is needed).&lt;br /&gt;
&lt;br /&gt;
We will describe two approaches to setting up a timer. The first method uses the &amp;lt;tt&amp;gt;sys_timerfd_*&amp;lt;/tt&amp;gt;&lt;br /&gt;
syscalls, which creates a file descriptor where reads block until the timer expires.&lt;br /&gt;
The second uses the &amp;lt;tt&amp;gt;sys_timer_*&amp;lt;/tt&amp;gt; syscalls, which send signals that can be caught by installing a signal handler.&lt;br /&gt;
The first method is usually smaller.&lt;br /&gt;
&lt;br /&gt;
==== Method 1: timerfd ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assume this is placed at the beginning of the program (all registers zeroed)&lt;br /&gt;
    mov ax,0x142 ; timerfd_create&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov ax,0x145 ; timerfd_settime&lt;br /&gt;
    push ebx&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov bl,3 ; file descriptor of timer (returned by timerfd_create)&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    ; assume eax &amp;lt; 256, ebx = 3, edx &amp;gt;= 8&lt;br /&gt;
    mov al,3&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int 0x80 ; block until next frame&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Method 2: signal handler ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming this is at the beginning of the program (all registers zeroed)&lt;br /&gt;
    call callback ; set up signal handler initially&lt;br /&gt;
&lt;br /&gt;
    ; assume eax &amp;lt; 65536, ebx = 1&lt;br /&gt;
    mov ax,0x103 ; timer_create&lt;br /&gt;
    dec ebx&lt;br /&gt;
    push ebx&lt;br /&gt;
    push 1 ; SIGHUP&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov ax,0x104 ; timer_settime&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp $ ; loop forever&lt;br /&gt;
&lt;br /&gt;
callback:&lt;br /&gt;
    ; assume eax &amp;lt; 256, ebx = 0&lt;br /&gt;
    mov al,0x30 ; signal&lt;br /&gt;
    inc ebx&lt;br /&gt;
    mov ecx,callback&lt;br /&gt;
    int 0x80 ; (re)install signal handler&lt;br /&gt;
    ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Allocating memory ===&lt;br /&gt;
&lt;br /&gt;
On many Linux distros, the stack size is limited to 8MB by default. If this is not enough for your intro,&lt;br /&gt;
it is possible to increase this stack limit or to allocate memory in the data segment.&lt;br /&gt;
&lt;br /&gt;
To allocate space in the data segment, you can use the brk system call (0x2d).&lt;br /&gt;
This call takes in a memory address and attempts to set the value of the current ''program break'' to that address,&lt;br /&gt;
then returns the new address. The program break is the smallest memory address that is beyond the data segment.&lt;br /&gt;
By default, the data segment is zero bytes long.&lt;br /&gt;
Unfortunately, on modern systems, the default value of the program break is &lt;br /&gt;
randomized, so you can't just simply call brk with the amount of memory you want.&lt;br /&gt;
Instead, you have to call brk with an address of zero to get the current program break,&lt;br /&gt;
then add the amount of memory you want and call brk with the new address.&lt;br /&gt;
The following code does this in 15 bytes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    xchg eax,ebx&lt;br /&gt;
    add ebx,0x1000000 ; allocate 16MB&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    ; eax now contains the address of the program break, i.e.,&lt;br /&gt;
    ; you can use memory from eax-0x1000000 to eax-1 (inclusive)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To increase the stack size limit, you can use the setrlimit (0x4b) system call.&lt;br /&gt;
The following 11-byte snippet will remove the stack size limit completely.&lt;br /&gt;
Note that in some cases the user will not have permission to do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    dec ecx ; ecx = -1 aka set size to 'unlimited'&lt;br /&gt;
    push ecx&lt;br /&gt;
    push ecx&lt;br /&gt;
    mov bl,3 ; RLIMIT_STACK&lt;br /&gt;
    mov ecx,esp ; pointer to data for call&lt;br /&gt;
    mov al,0x4b ; setrlimit&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Self modifying code ===&lt;br /&gt;
With the tiny ELF header we've been using, the code segment is not writable, and unfortunately we need to sacrifice some bytes to make it so.&lt;br /&gt;
So, in many cases it's better to avoid using self modifying code. But, if you want to try it out, there are two ways to go about it.&lt;br /&gt;
In the ELF header, the p_flags field stores the access permissions of the code memory (1=execute, 2=write, 4=read).&lt;br /&gt;
In the tiny header, p_flags overlaps with e_phoff, and e_phoff (the offset of the program header from the beginning of the file) needs to be 4.&lt;br /&gt;
So, the only option for p_flags is read-only (turns out that the execute bit doesn't matter, and it will be executable anyways).&lt;br /&gt;
To make the code writable, we have to change p_flags to 7 (6 and 3 also accomplish the same thing because some are implied by others).&lt;br /&gt;
To do this we can either use a less overlapped header, or we can use the mprotect syscall to change&lt;br /&gt;
the permissions.&lt;br /&gt;
&lt;br /&gt;
See here for examples of some headers that allow you to change p_flags: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html&lt;br /&gt;
&lt;br /&gt;
The mprotect method is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov eax,0x7d ; mprotect&lt;br /&gt;
    mov ebx,$$ ; start address to change permissions for&lt;br /&gt;
    mov ecx,0x1000 ; number of bytes to change&lt;br /&gt;
    mov edx,7 ; new permissions&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=970</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=970"/>
				<updated>2021-12-03T23:13:19Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Limiting FPS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method (method 1) is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method (method 2) uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers. Method 3, which saves some bytes over method 2 (especially when combined with visuals), is to use a shell based loader script.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pick apart the shell loader. Remember that in bash, $_ is the last argument passed to the previous command,&lt;br /&gt;
and $0 is the filename of the current executable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=shell&amp;gt;&lt;br /&gt;
cp $0 /tmp # copy the intro to /tmp&lt;br /&gt;
sed -i 1d $_/$0 # remove the first line from the copy with sed (aka remove the loader)&lt;br /&gt;
$_|aplay # execute the intro&lt;br /&gt;
rm $_ # remove the copy&lt;br /&gt;
exit # (so that the binary data which follows doesn't get executed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 11 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_ 0&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous Techniques ==&lt;br /&gt;
&lt;br /&gt;
=== Limiting FPS ===&lt;br /&gt;
&lt;br /&gt;
The framebuffer device /dev/fb0 will allow you to write to it as quickly as your CPU can manage,&lt;br /&gt;
so your intro can run at different speeds depending on the CPU speed. To correct this, you can use&lt;br /&gt;
a timer to limit FPS. Beyond limiting the frame rate, using a timer is seemingly necessary if you&lt;br /&gt;
want to have synchronized sound and graphics (but more research is needed).&lt;br /&gt;
&lt;br /&gt;
We will describe two approaches to setting up a timer. The first method uses the &amp;lt;tt&amp;gt;sys_timerfd_*&amp;lt;/tt&amp;gt;&lt;br /&gt;
syscalls, which creates a file descriptor where reads block until the timer expires.&lt;br /&gt;
The second uses the &amp;lt;tt&amp;gt;sys_timer_*&amp;lt;/tt&amp;gt; syscalls, which send signals that can be caught by installing a signal handler.&lt;br /&gt;
The first method is usually smaller.&lt;br /&gt;
&lt;br /&gt;
==== Method 1: timerfd ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assume this is placed at the beginning of the program (all registers zeroed)&lt;br /&gt;
    mov ax,0x142 ; timerfd_create&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov ax,0x145 ; timerfd_settime&lt;br /&gt;
    push ebx&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov bl,3 ; file descriptor of timer (returned by timerfd_create)&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    ; assume eax &amp;lt; 256, ebx = 3, edx &amp;gt;= 8&lt;br /&gt;
    mov al,3&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int 0x80 ; block until next frame&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Method 2: signal handler ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming this is at the beginning of the program (all registers zeroed)&lt;br /&gt;
    call callback ; set up signal handler initially&lt;br /&gt;
&lt;br /&gt;
    ; assume eax &amp;lt; 65536, ebx = 1&lt;br /&gt;
    mov ax,0x103 ; timer_create&lt;br /&gt;
    dec ebx&lt;br /&gt;
    push ebx&lt;br /&gt;
    push 1 ; SIGHUP&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov ax,0x104 ; timer_settime&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp $ ; loop forever&lt;br /&gt;
&lt;br /&gt;
callback:&lt;br /&gt;
    ; assume eax &amp;lt; 256, ebx = 0&lt;br /&gt;
    mov al,0x30 ; signal&lt;br /&gt;
    inc ebx&lt;br /&gt;
    mov ecx,callback&lt;br /&gt;
    int 0x80 ; (re)install signal handler&lt;br /&gt;
    ret&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Allocating memory ===&lt;br /&gt;
&lt;br /&gt;
On many Linux distros, the stack size is limited to 8MB by default. If this is not enough for your intro,&lt;br /&gt;
it is possible to increase this stack limit or to allocate memory in the data segment.&lt;br /&gt;
&lt;br /&gt;
To allocate space in the data segment, you can use the brk system call (0x2d).&lt;br /&gt;
This call takes in a memory address and attempts to set the value of the current ''program break'' to that address,&lt;br /&gt;
then returns the new address. The program break is the smallest memory address that is beyond the data segment.&lt;br /&gt;
By default, the data segment is zero bytes long.&lt;br /&gt;
Unfortunately, on modern systems, the default value of the program break is &lt;br /&gt;
randomized, so you can't just simply call brk with the amount of memory you want.&lt;br /&gt;
Instead, you have to call brk with an address of zero to get the current program break,&lt;br /&gt;
then add the amount of memory you want and call brk with the new address.&lt;br /&gt;
The following code does this in 15 bytes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    xchg eax,ebx&lt;br /&gt;
    add ebx,0x1000000 ; allocate 16MB&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    ; eax now contains the address of the program break, i.e.,&lt;br /&gt;
    ; you can use memory from eax-0x1000000 to eax-1 (inclusive)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To increase the stack size limit, you can use the setrlimit (0x4b) system call.&lt;br /&gt;
The following 11-byte snippet will remove the stack size limit completely.&lt;br /&gt;
Note that in some cases the user will not have permission to do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    dec ecx ; ecx = -1 aka set size to 'unlimited'&lt;br /&gt;
    push ecx&lt;br /&gt;
    push ecx&lt;br /&gt;
    mov bl,3 ; RLIMIT_STACK&lt;br /&gt;
    mov ecx,esp ; pointer to data for call&lt;br /&gt;
    mov al,0x4b ; setrlimit&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=969</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=969"/>
				<updated>2021-12-03T18:44:15Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: Add section about limiting fps&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method (method 1) is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method (method 2) uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers. Method 3, which saves some bytes over method 2 (especially when combined with visuals), is to use a shell based loader script.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pick apart the shell loader. Remember that in bash, $_ is the last argument passed to the previous command,&lt;br /&gt;
and $0 is the filename of the current executable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=shell&amp;gt;&lt;br /&gt;
cp $0 /tmp # copy the intro to /tmp&lt;br /&gt;
sed -i 1d $_/$0 # remove the first line from the copy with sed (aka remove the loader)&lt;br /&gt;
$_|aplay # execute the intro&lt;br /&gt;
rm $_ # remove the copy&lt;br /&gt;
exit # (so that the binary data which follows doesn't get executed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 11 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_ 0&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous Techniques ==&lt;br /&gt;
&lt;br /&gt;
=== Limiting FPS ===&lt;br /&gt;
&lt;br /&gt;
The framebuffer device /dev/fb0 will allow you to write to it as quickly as your CPU can manage,&lt;br /&gt;
so your intro can run at different speeds depending on the CPU speed. To correct this, you can use&lt;br /&gt;
a timer to limit FPS. Beyond limiting the frame rate, using a timer is seemingly necessary if you&lt;br /&gt;
want to have synchronized sound and graphics (but more research is needed).&lt;br /&gt;
&lt;br /&gt;
We will describe two approaches to setting up a timer. The first method uses the &amp;lt;tt&amp;gt;sys_timerfd_*&amp;lt;/tt&amp;gt;&lt;br /&gt;
syscalls, which creates a file descriptor where reads block until the timer expires.&lt;br /&gt;
The second uses the &amp;lt;tt&amp;gt;sys_timer_*&amp;lt;/tt&amp;gt; syscalls, which send signals that can be caught by installing a signal handler.&lt;br /&gt;
The first method is usually smaller.&lt;br /&gt;
&lt;br /&gt;
==== Method 1: timerfd ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assume this is placed at the beginning of the program&lt;br /&gt;
    mov ax,0x142 ; timerfd_create&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov ax,0x145 ; timerfd_settime&lt;br /&gt;
    push ebx&lt;br /&gt;
    push 1000000000/50 ; 50 fps&lt;br /&gt;
    push ebx&lt;br /&gt;
    mov bl,3 ; file descriptor of timer (returned by timerfd_create)&lt;br /&gt;
    mov edx,esp&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
main:&lt;br /&gt;
    mov al,3&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int 0x80 ; block until next frame&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Method 2: signal handler ====&lt;br /&gt;
&lt;br /&gt;
TODO&lt;br /&gt;
&lt;br /&gt;
=== Allocating memory ===&lt;br /&gt;
&lt;br /&gt;
On many Linux distros, the stack size is limited to 8MB by default. If this is not enough for your intro,&lt;br /&gt;
it is possible to increase this stack limit or to allocate memory in the data segment.&lt;br /&gt;
&lt;br /&gt;
To allocate space in the data segment, you can use the brk system call (0x2d).&lt;br /&gt;
This call takes in a memory address and attempts to set the value of the current ''program break'' to that address,&lt;br /&gt;
then returns the new address. The program break is the smallest memory address that is beyond the data segment.&lt;br /&gt;
By default, the data segment is zero bytes long.&lt;br /&gt;
Unfortunately, on modern systems, the default value of the program break is &lt;br /&gt;
randomized, so you can't just simply call brk with the amount of memory you want.&lt;br /&gt;
Instead, you have to call brk with an address of zero to get the current program break,&lt;br /&gt;
then add the amount of memory you want and call brk with the new address.&lt;br /&gt;
The following code does this in 15 bytes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    xchg eax,ebx&lt;br /&gt;
    add ebx,0x1000000 ; allocate 16MB&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    ; eax now contains the address of the program break, i.e.,&lt;br /&gt;
    ; you can use memory from eax-0x1000000 to eax-1 (inclusive)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To increase the stack size limit, you can use the setrlimit (0x4b) system call.&lt;br /&gt;
The following 11-byte snippet will remove the stack size limit completely.&lt;br /&gt;
Note that in some cases the user will not have permission to do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    dec ecx ; ecx = -1 aka set size to 'unlimited'&lt;br /&gt;
    push ecx&lt;br /&gt;
    push ecx&lt;br /&gt;
    mov bl,3 ; RLIMIT_STACK&lt;br /&gt;
    mov ecx,esp ; pointer to data for call&lt;br /&gt;
    mov al,0x4b ; setrlimit&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=968</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=968"/>
				<updated>2021-12-01T16:27:28Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Allocating memory */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method (method 1) is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method (method 2) uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers. Method 3, which saves some bytes over method 2 (especially when combined with visuals), is to use a shell based loader script.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pick apart the shell loader. Remember that in bash, $_ is the last argument passed to the previous command,&lt;br /&gt;
and $0 is the filename of the current executable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=shell&amp;gt;&lt;br /&gt;
cp $0 /tmp # copy the intro to /tmp&lt;br /&gt;
sed -i 1d $_/$0 # remove the first line from the copy with sed (aka remove the loader)&lt;br /&gt;
$_|aplay # execute the intro&lt;br /&gt;
rm $_ # remove the copy&lt;br /&gt;
exit # (so that the binary data which follows doesn't get executed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 11 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_ 0&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous Tricks ==&lt;br /&gt;
&lt;br /&gt;
=== Allocating memory ===&lt;br /&gt;
&lt;br /&gt;
On many Linux distros, the stack size is limited to 8MB by default. If this is not enough for your intro,&lt;br /&gt;
it is possible to increase this stack limit or to allocate memory in the data segment.&lt;br /&gt;
&lt;br /&gt;
To allocate space in the data segment, you can use the brk system call (0x2d).&lt;br /&gt;
This call takes in a memory address and attempts to set the value of the current ''program break'' to that address,&lt;br /&gt;
then returns the new address. The program break is the smallest memory address that is beyond the data segment.&lt;br /&gt;
By default, the data segment is zero bytes long.&lt;br /&gt;
Unfortunately, on modern systems, the default value of the program break is &lt;br /&gt;
randomized, so you can't just simply call brk with the amount of memory you want.&lt;br /&gt;
Instead, you have to call brk with an address of zero to get the current program break,&lt;br /&gt;
then add the amount of memory you want and call brk with the new address.&lt;br /&gt;
The following code does this in 15 bytes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    xchg eax,ebx&lt;br /&gt;
    add ebx,0x1000000 ; allocate 16MB&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    ; eax now contains the address of the program break, i.e.,&lt;br /&gt;
    ; you can use memory from eax-0x1000000 to eax-1 (inclusive)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To increase the stack size limit, you can use the setrlimit (0x4b) system call.&lt;br /&gt;
The following 11-byte snippet will remove the stack size limit completely.&lt;br /&gt;
Note that in some cases the user will not have permission to do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    dec ecx ; ecx = -1 aka set size to 'unlimited'&lt;br /&gt;
    push ecx&lt;br /&gt;
    push ecx&lt;br /&gt;
    mov bl,3 ; RLIMIT_STACK&lt;br /&gt;
    mov ecx,esp ; pointer to data for call&lt;br /&gt;
    mov al,0x4b ; setrlimit&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=967</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=967"/>
				<updated>2021-12-01T16:26:24Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Allocating memory */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method (method 1) is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method (method 2) uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers. Method 3, which saves some bytes over method 2 (especially when combined with visuals), is to use a shell based loader script.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pick apart the shell loader. Remember that in bash, $_ is the last argument passed to the previous command,&lt;br /&gt;
and $0 is the filename of the current executable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=shell&amp;gt;&lt;br /&gt;
cp $0 /tmp # copy the intro to /tmp&lt;br /&gt;
sed -i 1d $_/$0 # remove the first line from the copy with sed (aka remove the loader)&lt;br /&gt;
$_|aplay # execute the intro&lt;br /&gt;
rm $_ # remove the copy&lt;br /&gt;
exit # (so that the binary data which follows doesn't get executed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 11 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_ 0&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous Tricks ==&lt;br /&gt;
&lt;br /&gt;
=== Allocating memory ===&lt;br /&gt;
&lt;br /&gt;
On many Linux distros, the stack size is limited to 8MB by default. If this is not enough for your intro,&lt;br /&gt;
it is possible to increase this stack limit or to allocate memory in the data segment.&lt;br /&gt;
&lt;br /&gt;
To allocate space in the data segment, you can use the brk system call (0x2d).&lt;br /&gt;
This call takes in a memory address and attempts to set the value of the current ''program break'' to that address,&lt;br /&gt;
then returns the new address. The program break is the smallest memory address that is beyond the data segment.&lt;br /&gt;
By default, the data segment is zero bytes long.&lt;br /&gt;
Unfortunately, on modern systems, the default value of the program break is &lt;br /&gt;
randomized, so you can't just simply call brk with the amount of memory you want.&lt;br /&gt;
Instead, you have to call brk with an address of zero to get the current program break,&lt;br /&gt;
then add the amount of memory you want and call brk with the new address.&lt;br /&gt;
The following code does this in 17 bytes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    xchg eax,ebx&lt;br /&gt;
    add ebx,0x1000000 ; allocate 16MB&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    ; eax now contains the address of the program break, i.e.,&lt;br /&gt;
    ; you can use memory from eax-0x1000000 to eax-1 (inclusive)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To increase the stack size limit, you can use the setrlimit (0x4b) system call.&lt;br /&gt;
The following 11-byte snippet will remove the stack size limit completely.&lt;br /&gt;
Note that in some cases the user will not have permission to do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    dec ecx ; ecx = -1 aka set size to 'unlimited'&lt;br /&gt;
    push ecx&lt;br /&gt;
    push ecx&lt;br /&gt;
    mov bl,3 ; RLIMIT_STACK&lt;br /&gt;
    mov ecx,esp ; pointer to data for call&lt;br /&gt;
    mov al,0x4b ; setrlimit&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=966</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=966"/>
				<updated>2021-12-01T16:25:43Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Allocating memory */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method (method 1) is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method (method 2) uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers. Method 3, which saves some bytes over method 2 (especially when combined with visuals), is to use a shell based loader script.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pick apart the shell loader. Remember that in bash, $_ is the last argument passed to the previous command,&lt;br /&gt;
and $0 is the filename of the current executable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=shell&amp;gt;&lt;br /&gt;
cp $0 /tmp # copy the intro to /tmp&lt;br /&gt;
sed -i 1d $_/$0 # remove the first line from the copy with sed (aka remove the loader)&lt;br /&gt;
$_|aplay # execute the intro&lt;br /&gt;
rm $_ # remove the copy&lt;br /&gt;
exit # (so that the binary data which follows doesn't get executed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 11 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_ 0&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous Tricks ==&lt;br /&gt;
&lt;br /&gt;
=== Allocating memory ===&lt;br /&gt;
&lt;br /&gt;
On many Linux distros, the stack size is limited to 8MB by default. If this is not enough for your intro,&lt;br /&gt;
it is possible to increase this stack limit or to allocate memory in the data segment.&lt;br /&gt;
&lt;br /&gt;
To allocate space in the data segment, you can use the brk system call (0x2d).&lt;br /&gt;
This call takes in a memory address and attempts to set the value of the current ''program break'' to that address,&lt;br /&gt;
then returns the new address. The program break is the smallest memory address that is beyond the data segment.&lt;br /&gt;
By default, the data segment is zero bytes long.&lt;br /&gt;
Unfortunately, on modern systems, the default value of the program break is &lt;br /&gt;
randomized, so you can't just simply call brk with the amount of memory you want.&lt;br /&gt;
Instead, you have to call break with an address of zero to get the current program break,&lt;br /&gt;
then add the amount of memory you want and call brk with the new address.&lt;br /&gt;
The following code does this in 17 bytes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    xchg eax,ebx&lt;br /&gt;
    add ebx,0x1000000 ; allocate 16MB&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    ; eax now contains the address of the program break, i.e.,&lt;br /&gt;
    ; you can use memory from eax-0x1000000 to eax-1 (inclusive)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To increase the stack size limit, you can use the setrlimit (0x4b) system call.&lt;br /&gt;
The following 11-byte snippet will remove the stack size limit completely.&lt;br /&gt;
Note that in some cases the user will not have permission to do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    dec ecx ; ecx = -1 aka set size to 'unlimited'&lt;br /&gt;
    push ecx&lt;br /&gt;
    push ecx&lt;br /&gt;
    mov bl,3 ; RLIMIT_STACK&lt;br /&gt;
    mov ecx,esp ; pointer to data for call&lt;br /&gt;
    mov al,0x4b ; setrlimit&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=965</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=965"/>
				<updated>2021-12-01T16:25:02Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: Add section about allocating memory&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method (method 1) is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method (method 2) uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers. Method 3, which saves some bytes over method 2 (especially when combined with visuals), is to use a shell based loader script.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pick apart the shell loader. Remember that in bash, $_ is the last argument passed to the previous command,&lt;br /&gt;
and $0 is the filename of the current executable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=shell&amp;gt;&lt;br /&gt;
cp $0 /tmp # copy the intro to /tmp&lt;br /&gt;
sed -i 1d $_/$0 # remove the first line from the copy with sed (aka remove the loader)&lt;br /&gt;
$_|aplay # execute the intro&lt;br /&gt;
rm $_ # remove the copy&lt;br /&gt;
exit # (so that the binary data which follows doesn't get executed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 11 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_ 0&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous Tricks ==&lt;br /&gt;
&lt;br /&gt;
=== Allocating memory ===&lt;br /&gt;
&lt;br /&gt;
On many Linux distros, the stack size is limited to 8MB by default. If this is not enough for your intro,&lt;br /&gt;
it is possible to increase this stack limit to to allocate memory in the data segment.&lt;br /&gt;
&lt;br /&gt;
To allocate space in the data segment, you can use the brk system call (0x2d).&lt;br /&gt;
This call takes in a memory address and attempts to set the value of the current ''program break'' to that address,&lt;br /&gt;
then returns the new address. The program break is the smallest memory address that is beyond the data segment.&lt;br /&gt;
By default, the data segment is zero bytes long.&lt;br /&gt;
Unfortunately, on modern systems, the default value of the program break is &lt;br /&gt;
randomized, so you can't just simply call brk with the amount of memory you want.&lt;br /&gt;
Instead, you have to call break with an address of zero to get the current program break,&lt;br /&gt;
then add the amount of memory you want and call brk with the new address.&lt;br /&gt;
The following code does this in 17 bytes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    xchg eax,ebx&lt;br /&gt;
    add ebx,0x1000000 ; allocate 16MB&lt;br /&gt;
    mov al,0x2d&lt;br /&gt;
    int 0x80&lt;br /&gt;
    ; eax now contains the address of the program break, i.e.,&lt;br /&gt;
    ; you can use memory from eax-0x1000000 to eax-1 (inclusive)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To increase the stack size limit, you can use the setrlimit (0x4b) system call.&lt;br /&gt;
The following 11-byte snippet will remove the stack size limit completely.&lt;br /&gt;
Note that in some cases the user will not have permission to do this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    ; assuming all registers are zeroed, e.g., this is at the beginning of the program&lt;br /&gt;
    dec ecx ; ecx = -1 aka set size to 'unlimited'&lt;br /&gt;
    push ecx&lt;br /&gt;
    push ecx&lt;br /&gt;
    mov bl,3 ; RLIMIT_STACK&lt;br /&gt;
    mov ecx,esp ; pointer to data for call&lt;br /&gt;
    mov al,0x4b ; setrlimit&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=964</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=964"/>
				<updated>2021-11-30T16:40:12Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Method 3: shell loader */ fix syntax highlighting&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method (method 1) is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method (method 2) uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers. Method 3, which saves some bytes over method 2 (especially when combined with visuals), is to use a shell based loader script.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pick apart the shell loader. Remember that in bash, $_ is the last argument passed to the previous command,&lt;br /&gt;
and $0 is the filename of the current executable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=shell&amp;gt;&lt;br /&gt;
cp $0 /tmp # copy the intro to /tmp&lt;br /&gt;
sed -i 1d $_/$0 # remove the first line from the copy with sed (aka remove the loader)&lt;br /&gt;
$_|aplay # execute the intro&lt;br /&gt;
rm $_ # remove the copy&lt;br /&gt;
exit # (so that the binary data which follows doesn't get executed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 11 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_ 0&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=963</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=963"/>
				<updated>2021-11-30T05:50:00Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Adding Sound */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method (method 1) is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method (method 2) uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers. Method 3, which saves some bytes over method 2 (especially when combined with visuals), is to use a shell based loader script.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pick apart the shell loader. Remember that in bash, $_ is the last argument passed to the previous command,&lt;br /&gt;
and $0 is the filename of the current executable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cp $0 /tmp # copy the intro to /tmp&lt;br /&gt;
sed -i 1d $_/$0 # remove the first line from the copy with sed (aka remove the loader)&lt;br /&gt;
$_|aplay # execute the intro&lt;br /&gt;
rm $_ # remove the copy&lt;br /&gt;
exit # (so that the binary data which follows doesn't get executed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 11 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_ 0&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=962</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=962"/>
				<updated>2021-11-30T04:24:09Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Method 3: shell loader */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pick apart the shell loader. Remember that in bash, $_ is the last argument passed to the previous command,&lt;br /&gt;
and $0 is the filename of the current executable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cp $0 /tmp # copy the intro to /tmp&lt;br /&gt;
sed -i 1d $_/$0 # remove the first line from the copy with sed (aka remove the loader)&lt;br /&gt;
$_|aplay # execute the intro&lt;br /&gt;
rm $_ # remove the copy&lt;br /&gt;
exit # (so that the binary data which follows doesn't get executed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 11 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_ 0&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=961</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=961"/>
				<updated>2021-11-30T04:22:20Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Method 3: shell loader */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pick apart the shell loader. Remember that in bash, $_ is the last argument passed to the previous command,&lt;br /&gt;
and $0 is the filename of the current executable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cp $0 /tmp # copy the intro to /tmp&lt;br /&gt;
sed -i 1d $_/$0 # remove the first line from the copy with sed&lt;br /&gt;
$_|aplay # execute the intro&lt;br /&gt;
rm $_ # remove the copy&lt;br /&gt;
exit # exit (so that the binary data which follows doesn't get executed)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 11 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_ 0&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=960</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=960"/>
				<updated>2021-11-30T04:12:06Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: Add Method 3&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3: shell loader ===&lt;br /&gt;
&lt;br /&gt;
Everything we've seen so far has been focused on producing a &amp;quot;pure&amp;quot; ELF binary, to&lt;br /&gt;
avoid the compatibility issues that plagued early Linux sizecoding techniques involving self compilation or&lt;br /&gt;
binary patching. However, there is a way to embed the ELF binary in a shell script to&lt;br /&gt;
save some bytes without sacrificing compatibility.&lt;br /&gt;
&lt;br /&gt;
In method 1, we effectively moved the audio device handling out of the intro and put the&lt;br /&gt;
responsibility of connecting the intro to the audio device in the hands of the user.&lt;br /&gt;
This is obviously not ideal, and in method 2 we fixed this by opening the audio device&lt;br /&gt;
using syscalls. Here, we will use a hybrid approach. Our intro will appear to the&lt;br /&gt;
operating system as a shell script, which when executed will unpack the intro to /tmp&lt;br /&gt;
and then execute it, piping the output to aplay.&lt;br /&gt;
&lt;br /&gt;
The following example of this approach assembles to a 101-byte file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay&amp;quot;,10&lt;br /&gt;
org $00010000-($-$$)&lt;br /&gt;
top:&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd top ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    inc ebx ; we will write to stdout (1)&lt;br /&gt;
main:&lt;br /&gt;
    mov edx,esi ; copy time into edx&lt;br /&gt;
    pop ecx ; grab previous sample from stack&lt;br /&gt;
    ; bytebeat formula&lt;br /&gt;
    and ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    mov ebp,entry ; useless, skips part of ELF header&lt;br /&gt;
    xor ecx,edx&lt;br /&gt;
    shr edx,5&lt;br /&gt;
    or ecx,edx&lt;br /&gt;
    push ecx ; write next sample&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top byte of the stack)&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    inc esi ; increment time&lt;br /&gt;
&lt;br /&gt;
    jmp main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code will leave a file in /tmp after it exits, and will also write a bunch of garbage (the binary) to the screen when it exits.&lt;br /&gt;
Not only is this not very clean, but you may not be allowed to leave files around after your intro exits in some compos.&lt;br /&gt;
To fix this, we can use the following (slightly longer) shell loader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_|aplay;rm $_;exit&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Combining audio and video ====&lt;br /&gt;
&lt;br /&gt;
Although this method is already saving a lot of bytes, we haven't even gotten to the best part yet.&lt;br /&gt;
We can use the shell loader to also set up the framebuffer for us and make it very convenient to use, by using only 11 extra bytes!&lt;br /&gt;
To do this, just modify the loader as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    db &amp;quot;cp $0 /tmp;sed -i 1d $_/$0;$_ 0&amp;gt;/dev/fb0|aplay&amp;quot;,10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this loader, you can use pwrite64 directly on file descriptor 0 (stdin) to write to the screen, and write to file descriptor 1 (stdout) to play audio.&lt;br /&gt;
Just be careful to get the timing right if you're doing both audio and video, as the audio writes are blocking.&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=959</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=959"/>
				<updated>2021-11-29T21:57:12Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Method 2: pipe,fork,dup2,execve */ fix typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+8] ; get pointer to environ. this assumes only one dword has been popped so far,&lt;br /&gt;
                    ; and that there are no args passed to your program.&lt;br /&gt;
                    ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                    ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3 ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=958</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=958"/>
				<updated>2021-11-29T21:38:24Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Adding Sound */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+12] ; get pointer to environ. this assumes nothing has been&lt;br /&gt;
                     ; pushed/popped yet, and there are no args passed to your program.&lt;br /&gt;
                     ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                     ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Method 3 ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Playing MIDI ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
=== Syncing audio with visuals ===&lt;br /&gt;
&lt;br /&gt;
Coming soon...&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=957</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=957"/>
				<updated>2021-11-29T21:36:05Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Case study: 45-byte generative music intro */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely). The output is quite variable depending on the cycle counter, which is only reset when your computer powers on. So, try running it after different amounts of time since power-on, and you may be surprised how different it can sound!&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+12] ; get pointer to environ. this assumes nothing has been&lt;br /&gt;
                     ; pushed/popped yet, and there are no args passed to your program.&lt;br /&gt;
                     ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                     ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=956</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=956"/>
				<updated>2021-11-29T21:31:30Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Case study: 45-byte generative music intro */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
Which one is it? Well, the rdtsc instruction loads the low 32 bits of the CPU's&lt;br /&gt;
cycle counter into eax, and the high 32 bits into edx. So, whether we do a write&lt;br /&gt;
or not is effectively random depending on the current cycle count. Note that on&lt;br /&gt;
oldskool platforms, this may be quite deterministic, but on Linux the code is interrupted&lt;br /&gt;
many times a second, which causes effectively random fluctuations in the cycle count&lt;br /&gt;
that the program reads.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It ''writes'' to standard ''input''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
ecx is clearly set to equal esp, so the write syscall will be getting its data from the stack.&lt;br /&gt;
&lt;br /&gt;
edx, the amount of data to write, is a bit more tricky. It is set to the bitwise and of the low 32 and high 32 bits of the CPU's cycle counter (rdtsc).&lt;br /&gt;
This may seem problematic, because this number might be larger than the size of the stack. However, the write syscall will stop either after writing edx bytes,&lt;br /&gt;
or when it encounters a memory access violation. So, it doesn't matter if edx is huge, because then it will just write the entire contents of the stack.&lt;br /&gt;
&lt;br /&gt;
You may have noticed that the code has a &amp;lt;tt&amp;gt;push&amp;lt;/tt&amp;gt; instruction but no corresponding &amp;lt;tt&amp;gt;pop&amp;lt;/tt&amp;gt;. Won't it overflow the stack? Yes, eventually. But this takes quite a while.&lt;br /&gt;
&lt;br /&gt;
So, overall what the program is does is it pushes the low 32 bits of the CPU's cycle counter to the stack, then&lt;br /&gt;
randomly plays a variable length chunk of the stack as audio, or does nothing. This repeats until the stack overflows, which on my machine takes at least half an hour (note: you can change the stack size by running &amp;lt;tt&amp;gt;ulimit -s unlimited&amp;lt;/tt&amp;gt; beforehand, so that it will run until your RAM fills up completely).&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+12] ; get pointer to environ. this assumes nothing has been&lt;br /&gt;
                     ; pushed/popped yet, and there are no args passed to your program.&lt;br /&gt;
                     ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                     ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=955</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=955"/>
				<updated>2021-11-29T21:11:48Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: Clarify setting up section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, logging in and making sure the user is in the video group. &lt;br /&gt;
You can test if you are in the video group by running:&lt;br /&gt;
&lt;br /&gt;
    $ cp /dev/urandom /dev/fb0&lt;br /&gt;
&lt;br /&gt;
which should cause the screen to fill with white noise before printing &amp;quot;no space left on device&amp;quot;.&lt;br /&gt;
If this is not the case, you can add your user to the videogroup like so (substituting &amp;lt;tt&amp;gt;username&amp;lt;/tt&amp;gt; for your username):&lt;br /&gt;
&lt;br /&gt;
    $ sudo usermod -a -G video username&lt;br /&gt;
&lt;br /&gt;
After doing this you will need to log out and log back in for the changes to take effect.&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It '''writes''' to '''standard input'''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+12] ; get pointer to environ. this assumes nothing has been&lt;br /&gt;
                     ; pushed/popped yet, and there are no args passed to your program.&lt;br /&gt;
                     ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                     ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=954</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=954"/>
				<updated>2021-11-29T21:07:45Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: Fix typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the /dev/fb0 framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, login and making sure the user has access to the video group. If this is not the case for some reason, you can add your user to the videogroup like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
sudo usermod -a -G video username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It '''writes''' to '''standard input'''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+12] ; get pointer to environ. this assumes nothing has been&lt;br /&gt;
                     ; pushed/popped yet, and there are no args passed to your program.&lt;br /&gt;
                     ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                     ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=953</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=953"/>
				<updated>2021-11-29T19:57:37Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Case study: 45-byte generative music intro */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the dev/fbo framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, login and making sure the user has access to the video group. If this is not the case for some reason, you can add your user to the videogroup like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
sudo usermod -a -G video username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4; e_phoff, p_flags&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works...&lt;br /&gt;
&lt;br /&gt;
The first thing to notice that that the origin is 0x25500000, unlike the origin of 0x00010000 that we used before. This is intentional.&lt;br /&gt;
0x50 is the encoding of the &amp;lt;tt&amp;gt;push eax&amp;lt;/tt&amp;gt; instruction, which appears after &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt;,&lt;br /&gt;
and 0x25 is the first byte of the &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; instruction. These instructions actually overlap&lt;br /&gt;
with the e_entry field of the header, so the high two bytes of the entry point (and origin) must match these instructions.&lt;br /&gt;
The word &amp;lt;tt&amp;gt;0x001a&amp;lt;/tt&amp;gt; that appears immediately before &amp;lt;tt&amp;gt;entry:&amp;lt;/tt&amp;gt; forms the low two bytes of the entry point, i.e.,&lt;br /&gt;
&amp;lt;tt&amp;gt;0x001a == (entry-$$)&amp;amp;0xffff&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt; may seem odd, since this instruction is encoded as &amp;lt;tt&amp;gt;2504000000&amp;lt;/tt&amp;gt;, which&lt;br /&gt;
seems wasteful. However, doing &amp;lt;tt&amp;gt;and eax,4&amp;lt;/tt&amp;gt; (which only takes 3 bytes) would not work here, because the dword 4&lt;br /&gt;
needs to be stored here so that e_phoff (the program header offset) is correct.&lt;br /&gt;
&lt;br /&gt;
The rest of the code also overlaps the header, of course, but the fields that it overlaps are effectively ignored&lt;br /&gt;
when the program is loaded, so we don't need to worry about setting them to the correct values.&lt;br /&gt;
&lt;br /&gt;
Now, lets strip away the header and see why this code actually produces the sound it does:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax,strict dword 4&lt;br /&gt;
    mov ecx,esp&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Clearly, this code is calling some syscall (because of the &amp;lt;tt&amp;gt;int $80&amp;lt;/tt&amp;gt;), but which one is it calling?&lt;br /&gt;
The syscall number is stored in eax, and because of the instruction &amp;lt;tt&amp;gt;and eax,strict dword 4&amp;lt;/tt&amp;gt;&lt;br /&gt;
we know that eax must either be 4 or 0. Syscall 4 is the write syscall, which is what we want. But&lt;br /&gt;
what is syscall 0? The docs say that syscall 0 is &amp;lt;tt&amp;gt;restart_syscall&amp;lt;/tt&amp;gt;, which is used to&lt;br /&gt;
&amp;quot;restart a system call after interruption by a stop signal.&amp;quot; The man page says&lt;br /&gt;
&amp;quot;This system call is designed only for internal use by the kernel.&amp;quot; And, luckily&lt;br /&gt;
for us, when called from user space when the only other syscall we are using is write,&lt;br /&gt;
this has absolutely no effect, and will probably always return -1 (EINTR).&lt;br /&gt;
So, depending on eax&amp;amp;4, this code will either invoke the write syscall, or do nothing at all.&lt;br /&gt;
&lt;br /&gt;
The write syscall takes three arguments: the file to write to (in ebx), a pointer to the data to write (in ecx), and the amount of data to write (in edx).&lt;br /&gt;
The code doesn't even mention ebx at all, and it is zeroed at program start. So this program writes to file descriptor 0, which is standard input.&lt;br /&gt;
Now, that sounds weird. It '''writes''' to '''standard input'''? It turns out this is a perfectly fine thing to do, and we can redirect standard input to&lt;br /&gt;
standard output by using &amp;lt;tt&amp;gt;./daemon45 0&amp;gt;&amp;amp;1&amp;lt;/tt&amp;gt; on the command line.&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+12] ; get pointer to environ. this assumes nothing has been&lt;br /&gt;
                     ; pushed/popped yet, and there are no args passed to your program.&lt;br /&gt;
                     ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                     ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=952</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=952"/>
				<updated>2021-11-29T19:11:58Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: Adding section on simpler sound method&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the dev/fbo framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, login and making sure the user has access to the video group. If this is not the case for some reason, you can add your user to the videogroup like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
sudo usermod -a -G video username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved.&lt;br /&gt;
The simplest method is to write audio data to standard output and pipe it to aplay on the command line.&lt;br /&gt;
A more clean and self-contained method uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe to aplay on the command line ===&lt;br /&gt;
&lt;br /&gt;
The first method is the simplest, but will not be usable in all circumstances.&lt;br /&gt;
With this method, instead of running your intro with &amp;lt;tt&amp;gt;./intro&amp;lt;/tt&amp;gt;, you have to do &amp;lt;tt&amp;gt;./intro | aplay 2&amp;gt;/dev/null&amp;lt;/tt&amp;gt;,&lt;br /&gt;
which may not be allowed in some compos. However, with this method you can produce some extremely small generative music&lt;br /&gt;
intros, including some that are only 45 bytes---where the entire intro fits inside of the ELF header!&lt;br /&gt;
&lt;br /&gt;
Some basic code to produce a bytebeat sound is below.&lt;br /&gt;
It simply consists of a loop which repeatedly writes a single 8-bit audio sample to standard output using the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
audio:&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx ; grab previous sample from stack&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx ; push next sample to stack&lt;br /&gt;
&lt;br /&gt;
    mov ecx,esp ; pointer to audio data (the top of the stack)&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write syscall&lt;br /&gt;
    xor ebx,ebx&lt;br /&gt;
    inc ebx ; write to stdout (1)&lt;br /&gt;
    mov edx,ebx ; write 1 byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    jmp audio&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Case study: 45-byte generative music intro ====&lt;br /&gt;
&lt;br /&gt;
Below is the complete 45-byte generative music intro.&lt;br /&gt;
Try saving it in a file called daemon45.asm and running it with:&lt;br /&gt;
    $ nasm daemon45.asm&lt;br /&gt;
    $ chmod +x daemon45&lt;br /&gt;
    $ ./daemon45 0&amp;gt;&amp;amp;1 | aplay -fS32_LE -r16000 -c2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; daemon 45 by byteobserver&lt;br /&gt;
bits 32&lt;br /&gt;
org $25500000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dw $001a ; e_entry, p_memsz&lt;br /&gt;
entry:&lt;br /&gt;
    push eax&lt;br /&gt;
    and eax, strict dword 4; e_phoff-1, p_flags-1&lt;br /&gt;
    mov ecx,esp ; e_shoff, p_align&lt;br /&gt;
    int $80&lt;br /&gt;
    rdtsc ; e_flags&lt;br /&gt;
    and edx,eax&lt;br /&gt;
    loop entry ; e_ehsize&lt;br /&gt;
    dw $20 ; e_phentsize&lt;br /&gt;
    db 1 ; e_phnum&lt;br /&gt;
    ; e_shentsize&lt;br /&gt;
    ; e_shnum&lt;br /&gt;
    ; e_shstrndx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's pull this apart and see how it works... TODO.&lt;br /&gt;
&lt;br /&gt;
=== Method 2: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+12] ; get pointer to environ. this assumes nothing has been&lt;br /&gt;
                     ; pushed/popped yet, and there are no args passed to your program.&lt;br /&gt;
                     ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                     ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=951</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=951"/>
				<updated>2021-11-29T17:00:23Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Putting it all together */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the dev/fbo framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, login and making sure the user has access to the video group. If this is not the case for some reason, you can add your user to the videogroup like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
sudo usermod -a -G video username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved. One method uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+12] ; get pointer to environ. this assumes nothing has been&lt;br /&gt;
                     ; pushed/popped yet, and there are no args passed to your program.&lt;br /&gt;
                     ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                     ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    add ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=950</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=950"/>
				<updated>2021-11-29T16:59:32Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Putting it all together */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the dev/fbo framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, login and making sure the user has access to the video group. If this is not the case for some reason, you can add your user to the videogroup like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
sudo usermod -a -G video username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved. One method uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+12] ; get pointer to environ. this assumes nothing has been&lt;br /&gt;
                     ; pushed/popped yet, and there are no args passed to your program.&lt;br /&gt;
                     ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                     ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    mov ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    ; if you want to add more args to aplay, you can push pointers to them here&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=949</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=949"/>
				<updated>2021-11-29T16:55:22Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Adding Sound */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the dev/fbo framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, login and making sure the user has access to the video group. If this is not the case for some reason, you can add your user to the videogroup like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
sudo usermod -a -G video username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved. One method uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+12] ; get pointer to environ. this assumes nothing has been&lt;br /&gt;
                     ; pushed/popped yet, and there are no args passed to your program.&lt;br /&gt;
                     ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                     ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    mov ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
== Additional Resources ==&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=948</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=948"/>
				<updated>2021-11-29T16:53:36Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Adding Sound */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the dev/fbo framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, login and making sure the user has access to the video group. If this is not the case for some reason, you can add your user to the videogroup like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
sudo usermod -a -G video username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved. One method uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers.&lt;br /&gt;
&lt;br /&gt;
=== Method 1: pipe,fork,dup2,execve ===&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+12] ; get pointer to environ. this assumes nothing has been&lt;br /&gt;
                     ; pushed/popped yet, and there are no args passed to your program.&lt;br /&gt;
                     ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                     ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Putting it all together ====&lt;br /&gt;
&lt;br /&gt;
Combining the above snippets and optimizing a bit, we can arrive at&lt;br /&gt;
the following 118 byte program which plays a familiar bytebeat track.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1 ; p_type&lt;br /&gt;
    dd 0 ; p_offset&lt;br /&gt;
    dd $$ ; p_vaddr&lt;br /&gt;
    dw 2 ; e_type, p_paddr&lt;br /&gt;
    dw 3 ; e_machine&lt;br /&gt;
    dd entry ; e_version, p_filesz&lt;br /&gt;
    dd entry ; e_entry, p_memsz&lt;br /&gt;
    dd 4&lt;br /&gt;
entry:&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    mov ebx,esp ; store output of pipe on stack&lt;br /&gt;
    int 0x80&lt;br /&gt;
    lea edx,[ebx+12] ; environ pointer, to be used later&lt;br /&gt;
    mov ebp, entry ; e_phentsize, this must be here for the ELF header&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=childpid in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    pusha&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,eax ; input side of pipe created earlier&lt;br /&gt;
    lea ecx,[edx-12] ; pointer to audio data&lt;br /&gt;
    xor edx,edx&lt;br /&gt;
    inc edx ; set size to one byte&lt;br /&gt;
    int 0x80&lt;br /&gt;
    popa&lt;br /&gt;
&lt;br /&gt;
    ; some bytebeat&lt;br /&gt;
    inc esi&lt;br /&gt;
    mov eax,esi&lt;br /&gt;
    pop ebx&lt;br /&gt;
    mov ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    or ebx,eax&lt;br /&gt;
    shr eax,5&lt;br /&gt;
    and ebx,eax&lt;br /&gt;
    push ebx&lt;br /&gt;
&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&lt;br /&gt;
child:&lt;br /&gt;
    inc eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    ; ecx is already zero&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    lea ebx,[ebp+((aplay+5-entry)&amp;amp;0xff)] ; pointer to &amp;quot;aplay&amp;quot;&lt;br /&gt;
    push 0 ; null terminator for args list&lt;br /&gt;
    push ebx ; pointer to &amp;quot;aplay&amp;quot; aka argv[0]&lt;br /&gt;
    mov ecx,esp ; pointer to null terminated array of arguments&lt;br /&gt;
    mov bl,(aplay-$$)&amp;amp;0xff ; pointer to &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; edx is already set up as the environ pointer&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;&lt;br /&gt;
    ; no null terminator is necessary because memory past the end of the file is always zero&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Can you make this smaller? Feel free to edit it!''&lt;br /&gt;
&lt;br /&gt;
=== Additional Resources ===&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=947</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=947"/>
				<updated>2021-11-29T02:36:11Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: Add syntax highlighting to sound section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the dev/fbo framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, login and making sure the user has access to the video group. If this is not the case for some reason, you can add your user to the videogroup like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
sudo usermod -a -G video username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved. One method uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers.&lt;br /&gt;
&lt;br /&gt;
==== Method 1: pipe,fork,dup2,execve ====&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+12] ; get pointer to environ. this assumes nothing has been&lt;br /&gt;
                     ; pushed/popped yet, and there are no args passed to your program.&lt;br /&gt;
                     ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                     ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
&lt;br /&gt;
args:&lt;br /&gt;
    dd aplay+5&lt;br /&gt;
    dd 0&lt;br /&gt;
aplay:&lt;br /&gt;
    db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
parent:&lt;br /&gt;
&lt;br /&gt;
audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
=== Additional Resources ===&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=946</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=946"/>
				<updated>2021-11-29T01:54:19Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Adding Sound */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the dev/fbo framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, login and making sure the user has access to the video group. If this is not the case for some reason, you can add your user to the videogroup like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
sudo usermod -a -G video username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved. One method uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers.&lt;br /&gt;
&lt;br /&gt;
==== Method 1: pipe,fork,dup2,execve ====&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
    parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
    child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+12] ; get pointer to environ. this assumes nothing has been&lt;br /&gt;
                     ; pushed/popped yet, and there are no args passed to your program.&lt;br /&gt;
                     ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                     ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
    args:  dd aplay+5&lt;br /&gt;
           dd 0&lt;br /&gt;
    aplay: db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4). The following will produce a buzzing sound.&lt;br /&gt;
&lt;br /&gt;
    parent:&lt;br /&gt;
    audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
=== Additional Resources ===&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=945</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=945"/>
				<updated>2021-11-29T01:53:26Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Adding Sound */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the dev/fbo framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, login and making sure the user has access to the video group. If this is not the case for some reason, you can add your user to the videogroup like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
sudo usermod -a -G video username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved. One method uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers.&lt;br /&gt;
&lt;br /&gt;
==== Method 1: pipe,fork,dup2,execve ====&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
    &lt;br /&gt;
    parent:&lt;br /&gt;
    ; code for the rest of your intro goes here&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
    child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+12] ; get pointer to environ. this assumes nothing has been&lt;br /&gt;
                     ; pushed/popped yet, and there are no args passed to your program.&lt;br /&gt;
                     ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                     ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
    args:  dd aplay+5&lt;br /&gt;
           dd 0&lt;br /&gt;
    aplay: db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
    parent:&lt;br /&gt;
    audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
=== Additional Resources ===&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=944</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=944"/>
				<updated>2021-11-29T01:37:30Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: Writing linux audio section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the dev/fbo framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, login and making sure the user has access to the video group. If this is not the case for some reason, you can add your user to the videogroup like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
sudo usermod -a -G video username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
By default, aplay will play 8-bit mono audio at 8000Hz, but the format can be changed easily by specifying arguments.&lt;br /&gt;
If no filename is passed to aplay, it will read audio data from standard input, which we will use to our&lt;br /&gt;
advantage.&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved. One method uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers.&lt;br /&gt;
&lt;br /&gt;
==== Method 1: pipe,fork,dup2,execve ====&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors. The first file descriptor is the read only/output side and the second is the write only/input side.&lt;br /&gt;
&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2, because eax should already be zero (indicating that the pipe was created successfully).&lt;br /&gt;
&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
Now, we bind the standard input of the child (which aplay receives audio data from) to the output of the pipe, using the dup2 syscall (0x3f).&lt;br /&gt;
&lt;br /&gt;
    child:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x3f ; dup2&lt;br /&gt;
    pop ebx ; get file descriptor of output side of pipe&lt;br /&gt;
    xor ecx,ecx ; stdin is file descriptor 0&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
The following is optional. aplay will usually print a message saying&lt;br /&gt;
some parameters of the stream that it is playing. If this interferes&lt;br /&gt;
with your intro, you can close stderr to stop it from printing,&lt;br /&gt;
with the close syscall (0x6).&lt;br /&gt;
&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,6 ; close&lt;br /&gt;
    mov bl,2 ; stderr&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
Finally, we just have to execute aplay with the execve syscall (0xb).&lt;br /&gt;
Constructing the arguments to this syscall takes a bit of work.&lt;br /&gt;
Here we are doing it in a simple way which is a bit wasteful.&lt;br /&gt;
You can save some bytes by constructing the arguments array&lt;br /&gt;
on the stack.&lt;br /&gt;
&lt;br /&gt;
    xor eax,eax ; shouldn't be necessary given the above&lt;br /&gt;
    mov al,0xb ; execve&lt;br /&gt;
    mov ebx,aplay ; pointer to aplay filename&lt;br /&gt;
    mov ecx,args ; pointer to null terminated array of arguments&lt;br /&gt;
    lea edx,[esp+12] ; get pointer to environ. this assumes nothing has been&lt;br /&gt;
                     ; pushed/popped yet, and there are no args passed to your program.&lt;br /&gt;
                     ; see here: http://www.mindfruit.co.uk/2012/01/initial-stack-reading-process-arguments.html&lt;br /&gt;
                     ; (we are trying to get the beginning of &amp;quot;Environment pointers&amp;quot;)&lt;br /&gt;
    int 0x80 ; nothing after this point will be executed&lt;br /&gt;
    args:  dd aplay+5&lt;br /&gt;
           dd 0&lt;br /&gt;
    aplay: db &amp;quot;/bin/aplay&amp;quot;, 0&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up, and we can start writing audio data with the write syscall (0x4).&lt;br /&gt;
&lt;br /&gt;
    audioloop:&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,4 ; write&lt;br /&gt;
    mov ebx,[esp+4] ; input side of pipe created earlier&lt;br /&gt;
    mov ecx,esp ; pointer to audio data&lt;br /&gt;
    mov edx,1 ; length of audio data (in bytes)&lt;br /&gt;
    int 0x80&lt;br /&gt;
    inc byte [esp] ; increment the sample&lt;br /&gt;
    jmp audioloop&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
=== Additional Resources ===&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=943</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=943"/>
				<updated>2021-11-29T00:59:51Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: Starting on sound section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
'''1) Self-compilation tricks (using gcc or python):''' The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
'''2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup:''' This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
'''So what can we realistically expect from a 256 intro on Linux?'''&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Additionally, since we're dealing with 32-bit code, expect some instructions (especially when dealing with direct values) to take up bit more space.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the dev/fbo framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, login and making sure the user has access to the video group. If this is not the case for some reason, you can add your user to the videogroup like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
sudo usermod -a -G video username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehdr and phdr parts and changing your entry point, we can get the header down to about the 48 bytes range with a nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (2) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the aplay command into your intro.&lt;br /&gt;
aplay is available on almost all Linux setups. You can test it by running the following, which should produce some white noise:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
To use aplay in the context of an intro, there is a bit of setup work involved. One method uses 4 syscalls to start aplay&lt;br /&gt;
as a child process, so that audio data can then be simply written to the appropriate file descriptor to send it to&lt;br /&gt;
the speakers.&lt;br /&gt;
&lt;br /&gt;
==== Method 1: pipe,fork,dup2,execve ====&lt;br /&gt;
&lt;br /&gt;
This approach is as follows.&lt;br /&gt;
First, we create a pipe using the pipe syscall (0x2a).&lt;br /&gt;
This syscall takes a pointer to an array of 2 ints, which it fills with&lt;br /&gt;
the file descriptors of the two ends of the pipe. In the following,&lt;br /&gt;
we simply overwrite the top of the stack with the file descriptors.&lt;br /&gt;
&lt;br /&gt;
    mov ebx,esp&lt;br /&gt;
    xor eax,eax&lt;br /&gt;
    mov al,0x2a ; pipe&lt;br /&gt;
    int 0x80&lt;br /&gt;
&lt;br /&gt;
Next, we fork the process (syscall 0x2). The child process will be used to exec aplay.&lt;br /&gt;
If you do this right after creating the pipe, you don't need to zero eax before setting it to 2.&lt;br /&gt;
&lt;br /&gt;
    mov al,2 ; fork&lt;br /&gt;
    int 0x80 ; returns eax=0 in child process and eax=1 in parent process&lt;br /&gt;
    dec eax&lt;br /&gt;
    js child&lt;br /&gt;
&lt;br /&gt;
=== Additional Resources ===&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics A dev/fb0 framebuffer binding + ELF header for small C programs]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=882</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=882"/>
				<updated>2021-08-09T04:38:40Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Adding Sound */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This section of the sizecoding.org wiki is about creating very small (&amp;lt;=256byte) 32-bit X86 based Linux binaries (ELF format).&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 Linux sizecoding. &lt;br /&gt;
&lt;br /&gt;
A huge thanks goes out to byteobserver (Xorchitecture (2021) - https://www.pouet.net/prod.php?which=88982) as well as some early work by frag/fsqrt (Lintro (2012) - https://www.pouet.net/prod.php?which=58560) for all their research and hard work in producing tiny ELF binaries for linux.&lt;br /&gt;
&lt;br /&gt;
=== Alternative methods and expectations ===&lt;br /&gt;
As the development of actual tiny ELF assembler executables on linux is still in its early days, with about a handful of actual &amp;lt;256 byte tiny ELF binary productions, lets look at some of the other methods of getting tiny intros onto linux.&lt;br /&gt;
&lt;br /&gt;
1) Self-compilation tricks (using gcc or python): The executable executes a gcc (or python) compilation of the embedded code and executes it. This requires GCC and/or specific version of Python and potentially dynamically linked libraries to be installed. &lt;br /&gt;
&lt;br /&gt;
2) Linking a piece of compiled C code to a stripped ELF header + dev/fb0 setup: This method has been used by The Orz to create&lt;br /&gt;
several sizecoded procedural graphics entries. For more information about this check out https://github.com/grz0zrg/tinycelfgraphics&lt;br /&gt;
&lt;br /&gt;
So what can we realistically expect from a 256 intro on Linux?&lt;br /&gt;
&lt;br /&gt;
Expect about ~100 byte cost for the ELF header, setting up fb0 , some form of update loop, framecounter and using either mmap setup or copying via pwrite64 to get you started. If you want audio as well, the avaialble byte-budget will shrink even more.&lt;br /&gt;
&lt;br /&gt;
Lets hope this wiki page will inspire and help people to get started and create newer, better Linux tiny intros ;-)&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : Any X86-based Linux distribution that allows for execution of 32-bit executables.&lt;br /&gt;
* Assembler: NASM (or any other linux compatible 32-bit X86 assembler)&lt;br /&gt;
&lt;br /&gt;
Furthermore, it is important that the user has access to the dev/fbo framebuffer.&lt;br /&gt;
This can be achieved by launching a virtual (fullscreen) console using CTRL-F3/F4 in most distributions, login and making sure the user has access to the video group. If this is not the case for some reason, you can add your user to the videogroup like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
sudo usermod -a -G video username&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: Make sure your binary is executable for everyone using the chmod 777 command after compilation :D&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
Interaction with the Linux OS is mostly done via int 0x80 system calls.&lt;br /&gt;
This usually includes dealing with opening files/framebuffer/audio and handling timers.&lt;br /&gt;
&lt;br /&gt;
A full list of system calls and their expected register arguments is available at:&lt;br /&gt;
https://syscalls32.paolostivanin.com/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
Like a 32-bit windows executable, a 32-bit binary for linux comes with a pretty hefty ELF header.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
  org     0x00010000  &lt;br /&gt;
  ehdr:                                                 ; Elf32_Ehdr&lt;br /&gt;
                db      0x7F, &amp;quot;ELF&amp;quot;, 1, 1, 1, 0         ;   e_ident&lt;br /&gt;
        times 8 db      0&lt;br /&gt;
                dw      2                               ;   e_type&lt;br /&gt;
                dw      3                               ;   e_machine&lt;br /&gt;
                dd      1                               ;   e_version&lt;br /&gt;
                dd      _start                          ;   e_entry&lt;br /&gt;
                dd      phdr - $$                       ;   e_phoff&lt;br /&gt;
                dd      0                               ;   e_shoff&lt;br /&gt;
                dd      0                               ;   e_flags&lt;br /&gt;
                dw      ehdrsize                        ;   e_ehsize&lt;br /&gt;
                dw      phdrsize                        ;   e_phentsize&lt;br /&gt;
                dw      1                               ;   e_phnum&lt;br /&gt;
                dw      0                               ;   e_shentsize&lt;br /&gt;
                dw      0                               ;   e_shnum&lt;br /&gt;
                dw      0                               ;   e_shstrndx&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  phdr:                                                 ; Elf32_Phdr&lt;br /&gt;
                dd      1                               ;   p_type&lt;br /&gt;
                dd      0                               ;   p_offset&lt;br /&gt;
                dd      $$                              ;   p_vaddr&lt;br /&gt;
                dd      $$                              ;   p_paddr&lt;br /&gt;
                dd      filesize                        ;   p_filesz&lt;br /&gt;
                dd      filesize                        ;   p_memsz&lt;br /&gt;
                dd      5                               ;   p_flags&lt;br /&gt;
                dd      0x1000                          ;   p_align&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  _start:&lt;br /&gt;
  &lt;br /&gt;
  ; your program here&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luckily some parts of the ELF header can be repurposed and used to store some data and code.&lt;br /&gt;
There is quite an extensive journey about some header optimisations available at http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html for those that are interested.&lt;br /&gt;
&lt;br /&gt;
After merging the ehr and phr parts and changing your entry point, we can get the header down to about the 30 bytes range with a &lt;br /&gt;
nifty /dev/fb0 string inserted which we'll be able to use later for setting up the framebuffer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot;    ; e_ident&lt;br /&gt;
    dd 1            ; p_type&lt;br /&gt;
    dd 0            ; p_offset&lt;br /&gt;
    dd $$           ; p_vaddr&lt;br /&gt;
    dw 2            ; e_type, p_paddr&lt;br /&gt;
    dw 3            ; e_machine&lt;br /&gt;
    dd entry        ; e_version, p_filesz&lt;br /&gt;
    dd entry        ; e_entry, p_memsz&lt;br /&gt;
    dd 4            ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    ; this next instruction overlaps with a critical part of the elf header&lt;br /&gt;
    ; it needs to look like XX YY YY YY YY where YYYYYYYY=fname&lt;br /&gt;
    ; so you can change the register to something else or use push&lt;br /&gt;
    ; but the four byte pointer to fname cannot be changed.&lt;br /&gt;
    mov ebx,fname   ; e_phentsize, e_phnum&lt;br /&gt;
&lt;br /&gt;
    ; e_shentsize, e_shnum, e_shstrndx are below but we can put whatever code/bytes we want there&lt;br /&gt;
    mov cl,1 ; set read/write mode (1 or inc ecx is sufficient for pcopy method, read/write (3) is needed for mmap)&lt;br /&gt;
    mov al,5 ; 5 = open syscall&lt;br /&gt;
    int 0x80 ; open /dev/fb0 = 3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Displaying Graphics ==&lt;br /&gt;
Graphics can be produced by using and accessing the linux /dev/fb0 framebuffer.&lt;br /&gt;
First the framebuffer has to be opened at the intro initialisation, and can then be used to either copy a piece of memory over using the pwrite64 syscall (0xb5) or using map a piece of memory directly to the framebuffer using syscall mmap (90)&lt;br /&gt;
&lt;br /&gt;
==== Setting up the framebuffer ====&lt;br /&gt;
The dev/fb0 framebuffer can best be accessed from a virtual console (ctrl-f3/f4 in most distributions).&lt;br /&gt;
&lt;br /&gt;
To make sure your dev/fb0 framebuffer is set up properly, you can apt get the fbset tool and display and/or alter the framebuffer resolution as most intros will make an assumption about the resolution of your framebuffer.&lt;br /&gt;
&lt;br /&gt;
To test access to dev/fb0 framebuffer, you can use the following cat command:&lt;br /&gt;
&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
cat /dev/urandom &amp;gt; /dev/fb0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
which should produce random noise to the screen (ignorning the out of memory error that is expected from cat) &lt;br /&gt;
&lt;br /&gt;
Alternatively, if you don't like to use the virtual console during the development of your intro, or the framebuffer setup is somehow giving you problems, there is a smalle fbe.c / fbe binary supplied with the xorchitecture intro by byteobserver that has a SDL windows mmap'ed to tmp/fb0 which you can launch alongside your intro (don't forget to redirect the dev/fb0 pointer in your intro to tmp/fb0).&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
First we need to fill up our local memorybuffer with pixeldata, so lets start doing that using the old AND pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
    mov ecx,width*height&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    and eax,edx           ; xor pattern&lt;br /&gt;
&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your buffer (in this case marked by the esp stackpointer) is all filled up with pixeldata, you &lt;br /&gt;
can copy it to the /dev/fb0 using the pwrite64 syscall like so: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
   ; copy memorybuffer to screen (/dev/fb0) using the pwrite64 syscall&lt;br /&gt;
   mov ecx,esp  ; buffer ptr&lt;br /&gt;
   mov edx,ebp  ; screen size&lt;br /&gt;
   xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
   xor edi,edi  &lt;br /&gt;
   mov ebx,3    ; fd of framebuffer&lt;br /&gt;
   mov eax,0xb5 ; pwrite64&lt;br /&gt;
   int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As an alternative to using pwrite64 you can also mmap )check out intros by The Orz for an example with mmap) to map &lt;br /&gt;
a piece of memory to dev/fb0. However using mmap because you can get tearing, and you can't realistically do feedback effects without implementing a second buffer, as reading from the mmaped memory is VERY slow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
 ;mmap(NULL, buflen, PROT_WRITE, MAP_SHARED, fd, 0);&lt;br /&gt;
 push edx	      ;edx = 0&lt;br /&gt;
 push eax	      ;fd&lt;br /&gt;
 push byte 1	      ;MAP_SHARED&lt;br /&gt;
 mov al, 90&lt;br /&gt;
 push eax	      ;we need to set second bit for PROT_WRITE, 90 = 01011010 and setting PROT_WRITE automatically set PROT_READ&lt;br /&gt;
 push width*height*4  ;buffer size&lt;br /&gt;
 push edx	      ;NULL&lt;br /&gt;
 mov ebx, esp	  ;args pointer&lt;br /&gt;
 int 80h		      ;eax &amp;lt;- buffer pointer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Example Framework ==&lt;br /&gt;
&lt;br /&gt;
==== Munching squares ====&lt;br /&gt;
So when we put all the above together, we can get a minimal kind of framework running that will look something like this&lt;br /&gt;
munching square example provided to us by byteobserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=nasm&amp;gt;&lt;br /&gt;
; byte.observer's munching square linux example&lt;br /&gt;
; assembles with nasm -fbin munch.asm -o munch&lt;br /&gt;
width equ 1024&lt;br /&gt;
height equ 768&lt;br /&gt;
&lt;br /&gt;
bits 32&lt;br /&gt;
org $00010000&lt;br /&gt;
    db $7F,&amp;quot;ELF&amp;quot; ; e_ident&lt;br /&gt;
    dd 1         ; p_type&lt;br /&gt;
    dd 0         ; p_offset&lt;br /&gt;
    dd $$        ; p_vaddr&lt;br /&gt;
    dw 2         ; e_type, p_paddr&lt;br /&gt;
    dw 3         ; e_machine&lt;br /&gt;
    dd entry     ; e_version, p_filesz&lt;br /&gt;
    dd entry     ; e_entry, p_memsz&lt;br /&gt;
    dd 4         ; e_phoff, p_flags&lt;br /&gt;
fname:&lt;br /&gt;
    db &amp;quot;/dev/fb0&amp;quot;,0 ; e_shoff, p_align, e_flags, e_ehsize&lt;br /&gt;
entry:&lt;br /&gt;
    mov ebx,fname     ; e_phentsize, e_phnum&lt;br /&gt;
    inc ecx           ; = 1 = O_WRONLY&lt;br /&gt;
    mov al,5          ; 5 = open syscall&lt;br /&gt;
    int 0x80          ; open /dev/fb0 = 3&lt;br /&gt;
&lt;br /&gt;
    mov ebp,width*height*4  ; ebp = screen size&lt;br /&gt;
    sub esp,ebp             ; make room on the stack for the video memory&lt;br /&gt;
&lt;br /&gt;
mainloop:&lt;br /&gt;
    mov ecx,ebp    ; init pixel index&lt;br /&gt;
    shr ecx,2      ; divide by bits per pixel&lt;br /&gt;
    inc edi        ; frame counter&lt;br /&gt;
&lt;br /&gt;
setpixels:&lt;br /&gt;
    mov ebx,width&lt;br /&gt;
    mov eax,ecx&lt;br /&gt;
    cdq&lt;br /&gt;
    div ebx               ; edx = x-coord , eax=y coord&lt;br /&gt;
    xor eax,edx           ; xor pattern&lt;br /&gt;
    add eax,edi           ; make it munch&lt;br /&gt;
    mov [esp+ecx*4+0],al ; b&lt;br /&gt;
    mov [esp+ecx*4+1],al ; g&lt;br /&gt;
    mov [esp+ecx*4+2],al ; r&lt;br /&gt;
    mov [esp+ecx*4+3],al ; a&lt;br /&gt;
    loop setpixels&lt;br /&gt;
&lt;br /&gt;
    ; dump the whole thing to the screen using pwrite64 syscall&lt;br /&gt;
    mov ecx,esp  ; buffer ptr&lt;br /&gt;
    mov edx,ebp  ; screen size&lt;br /&gt;
    push edi     ; save frame counter&lt;br /&gt;
    xor esi,esi  ; seek to beginning of screen&lt;br /&gt;
    xor edi,edi  &lt;br /&gt;
    mov ebx,3    ; fd of framebuffer&lt;br /&gt;
    mov eax,0xb5 ; pwrite64&lt;br /&gt;
    int 0x80     ; pwrite64 to framebuffer&lt;br /&gt;
    pop edi&lt;br /&gt;
&lt;br /&gt;
    jmp mainloop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adding Sound ==&lt;br /&gt;
It is possible to output digital audio by binding the the aplay command into your intro.&lt;br /&gt;
APLAY is available on most of the Linux distributions and can be tested by running:&lt;br /&gt;
&lt;br /&gt;
    $ aplay /dev/urandom&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Make some noise ====&lt;br /&gt;
To be added soon.&lt;br /&gt;
&lt;br /&gt;
=== Additional Resources ===&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics] A dev/fb0 framebuffer binding + ELF header for small C programs.&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
&lt;br /&gt;
== Larger productions (1k and 4k intros) ==&lt;br /&gt;
Creating 1k and 4k intros on linux usually requires a different setup, for more information on this check out the following links:&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	<entry>
		<id>http://www.sizecoding.org/index.php?title=Linux&amp;diff=846</id>
		<title>Linux</title>
		<link rel="alternate" type="text/html" href="http://www.sizecoding.org/index.php?title=Linux&amp;diff=846"/>
				<updated>2021-03-17T01:33:29Z</updated>
		
		<summary type="html">&lt;p&gt;Byteobserver: /* Additional Resources */ Add additional links&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
For X86 related information, please check the main pages on this website, as a lot of the same tricks will also work with X86 linux sizecoding. This page goes into the specifics of getting small binaries on linux. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Linux system ===&lt;br /&gt;
To be added.&lt;br /&gt;
&lt;br /&gt;
=== Setting up ===&lt;br /&gt;
Setting up your development platform for Linux development:&lt;br /&gt;
&lt;br /&gt;
* Suggested Distributions : -&lt;br /&gt;
* Assembler: NASM (?)&lt;br /&gt;
&lt;br /&gt;
=== ELF Header Information ===&lt;br /&gt;
To be added.&lt;br /&gt;
&lt;br /&gt;
=== System Calls ===&lt;br /&gt;
To be added.&lt;br /&gt;
&lt;br /&gt;
=== Self compilation ===&lt;br /&gt;
To be added.&lt;br /&gt;
&lt;br /&gt;
== Accessing video ==&lt;br /&gt;
Accessing video&lt;br /&gt;
&lt;br /&gt;
==== Getting something on screen ====&lt;br /&gt;
To be added soon.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Sound ==&lt;br /&gt;
To be added soon.&lt;br /&gt;
&lt;br /&gt;
==== Make some noise ====&lt;br /&gt;
To be added soon.&lt;br /&gt;
&lt;br /&gt;
=== Additional Resources ===&lt;br /&gt;
* [https://pcy.ulyssis.be/pres/Lin.pdf The Intricacies of Sizecoding on Linux (PDF)]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=128b&amp;amp;platform%5B%5D=Linux Pouet: 128byte productions on Linux]&lt;br /&gt;
* [https://www.pouet.net/prodlist.php?type%5B%5D=256b&amp;amp;platform%5B%5D=Linux Pouet: 256byte productions on Linux]&lt;br /&gt;
* [https://github.com/grz0zrg/tinycelfgraphics Collection of tiny C ELF programs with graphics output]&lt;br /&gt;
* [http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux]&lt;br /&gt;
* [https://linux.weeaboo.software/Home Linux Sizecoding wiki at weeaboo.software]&lt;/div&gt;</summary>
		<author><name>Byteobserver</name></author>	</entry>

	</feed>