%include "SYS.macros" global start section .text start: ;; The reason for this bit about mprotect(2) is that by default these days ;; the .text segment is not writable. I tried objcopy --writable-text, but ;; that seems to have no effect, and this is better anyway (I hope) in that ;; it puts everything in one place. mov ebx,start ; try to get a page boundary for this section, the text section/segment and ebx,0xfffff800 ; .... SYS_MPROTECT ebx,0x00000001,PROT_READ|PROT_WRITE|PROT_EXEC ;; Tell the user what's going on SYS_WRITE 1,msg1,msg1len SYS_OPEN maps,O_RDONLY,0x0 ; okay, let's see if we can read our own /proc/self/maps file... mov [mapsfd],eax ; save file descriptor in [mapsfd] SYS_READ [mapsfd],somedata,4096 ; I hope that open(2) did leave a useful file descriptor in eax SYS_WRITE 1,somedata,eax SYS_CLOSE [mapsfd] ;; Establish a heap SYS_BRK 0 add eax,1000 SYS_BRK eax ;; Tell the user SYS_WRITE 1,msg2,msg2len SYS_OPEN maps,O_RDONLY,0x0 ; okay, let's see if we can read our own /proc/self/maps file... mov [mapsfd],eax ; save file descriptor in [mapsfd] SYS_READ [mapsfd],somedata,4096 ; I hope that open(2) did leave a useful file descriptor in eax SYS_WRITE 1,somedata,eax SYS_CLOSE [mapsfd] ;; Create a mmap SYS_MMAP2 0,1024,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_ANONYMOUS|MAP_PRIVATE,-1,0 mov [mmapaddr],eax ; preserve the return for later... ;; Tell the user SYS_WRITE 1,msg3,msg3len SYS_OPEN maps,O_RDONLY,0x0 ; okay, let's see if we can read our own /proc/self/maps file... mov [mapsfd],eax ; save file descriptor in [mapsfd] SYS_READ [mapsfd],somedata,4096 ; I hope that open(2) did leave a useful file descriptor in eax SYS_WRITE 1,somedata,eax SYS_CLOSE [mapsfd] ;; Create a second mmap. Have to actually specify an address some distance away, or ;; the kernel will just extend the first mmap-ing mov ebx,[mmapaddr] sub ebx,4096*10 SYS_MMAP2 ebx,1024,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_ANONYMOUS|MAP_PRIVATE,-1,0 ;; Tell the user SYS_WRITE 1,msg4,msg4len SYS_OPEN maps,O_RDONLY,0x0 ; okay, let's see if we can read our own /proc/self/maps file... mov [mapsfd],eax ; save file descriptor in [mapsfd] SYS_READ [mapsfd],somedata,4096 ; I hope that open(2) did leave a useful file descriptor in eax SYS_WRITE 1,somedata,eax SYS_CLOSE [mapsfd] SYS_EXIT 0 ;; data ---> But note that we are actually using the text segment to store this! We use mprotect(2) ;; to make it writable so that we can retrieve data from /proc/self/maps, buffer it in somedata, and then ;; write it. It is also used for a utility double word to save our first mmap's base address. ;; Strings first maps: db '/proc/self/maps',0 mapsfd: dd 0 msg1: db 'This program demonstrates that neither a heap nor a data segment are necessary components',10 db 'of a Linux process (indeed, this process is using its text segment to store its temporary data!)',10,10 db 'The only necessary components are the text segment (where the running code and temporary',10 db 'data are), a stack, and a vdso.',10,10 db 'Here is your initial memory mapping from /proc/self/maps -- please note that there is no data',10 db 'or heap section, just a vdso and stack:',10,10 msg1len equ $ - msg1 msg2: db 10,'Now we will create a heap by calling brk(2) twice.',10,10 db 'Okay, that is done. Let us look at our new map:',10,10 msg2len equ $ - msg2 msg3: db 10,10,'Now we use mmap2(2) to create yet another segment, an anonymous memory mapping:',10,10 msg3len equ $ - msg3 msg4: db 10,10,'Now we use mmap2(2) to create a second anonymous memory mapping segment:',10,10 msg4len equ $ - msg4 ;; A bit of space to save our first mmap's base address mmapaddr: dd 0 ;; Finally, a buffer for /proc/self/maps data somedata: times 4096 db 0