Linux用の1k / 4kイントロの作成、パート2

半年も経っていません! 緊張して、記憶に残るように私たちが最後に落胆とアセンブラーに飛び込む約束に落ち着いたとき 、あなたはそうすることができます。

まあ、少年は言った-少年はやった。 この不格好な文字の山から、GNU / LinuxのOpenGLコンテキストを約450バイトに初期化し、才能を展開するためのスペースをさらに解放する方法を学習します。



カットの下で、このようなものを1キロバイトで描画する方法を学習します。





興味のある人は、ペダルを床に固定して押し、目を画面に向けます。





始めるために、それについて話しましょう。 なぜ私たちはそんなに悪いと価値がないのですか? 何が正確に私たちに重みを追加し、劣化の深さに私たちを引き下げますか?

これらの質問に答えるには、本物の男性のためのツール、readelfとobjdumpが必要です。



最初のファイルを見つけて、最後にイントロファイルを設定します。これは、sstripファイルで処理した後も同じです。



$ readelf -a intro ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Intel 80386 Version: 0x1 Entry point address: 0x8048250 Start of program headers: 52 (bytes into file) Start of section headers: 0 (bytes into file) Flags: 0x0 Size of this header: 52 (bytes) Size of program headers: 32 (bytes) Number of program headers: 8 Size of section headers: 40 (bytes) Number of section headers: 0 Section header string table index: 0 There are no sections in this file. There are no sections in this file. Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000034 0x08048034 0x08048034 0x00100 0x00100 RE 0x4 INTERP 0x000134 0x08048134 0x08048134 0x00015 0x00015 R 0x1 [Requesting program interpreter: /lib32/ld-linux.so.2] LOAD 0x000000 0x08048000 0x08048000 0x005ac 0x005ac RE 0x1000 LOAD 0x000f4c 0x08049f4c 0x08049f4c 0x000c4 0x00100 RW 0x1000 DYNAMIC 0x000f4c 0x08049f4c 0x08049f4c 0x000a8 0x000a8 RW 0x4 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4 GNU_RELRO 0x000f4c 0x08049f4c 0x08049f4c 0x000b4 0x000b4 R 0x1 PAX_FLAGS 0x000000 0x00000000 0x00000000 0x00000 0x00000 0x4 Dynamic section at offset 0xf4c contains 16 entries: Tag Type Name/Value 0x00000001 (NEEDED) Shared library: [libdl.so.2] 0x00000004 (HASH) 0x804814c 0x6ffffef5 (GNU_HASH) 0x8048164 0x00000005 (STRTAB) 0x80481ac 0x00000006 (SYMTAB) 0x804817c 0x0000000a (STRSZ) 45 (bytes) 0x0000000b (SYMENT) 16 (bytes) 0x00000015 (DEBUG) 0x0 0x00000003 (PLTGOT) 0x8049ff4 0x00000002 (PLTRELSZ) 16 (bytes) 0x00000014 (PLTREL) REL 0x00000017 (JMPREL) 0x8048210 0x6ffffffe (VERNEED) 0x80481e0 0x6fffffff (VERNEEDNUM) 1 0x6ffffff0 (VERSYM) 0x80481da 0x00000000 (NULL) 0x0 There are no relocations in this file. There are no unwind sections in this file. Histogram for bucket list length (total of 1 buckets): Length Number % of total Coverage 0 0 ( 0.0%) 1 0 ( 0.0%) 0.0% 2 1 (100.0%) 100.0% No version information found in this file.
      
      





(特定の数、サイズ、オフセットは、ツールチェーン全体とマイルの年齢メイバーバラに依存します)

ここで何が見えますか? もちろん、最初の段階では、標準のELFヘッダーであるため、そこから言葉を放り出すことはありません。 次に、sstripがすべてのセクションヘッダーをスクラッチしたことがわかります(演習:出力をreadelf -a intro-orig(sstripの前)と比較してください)。 しかし、その後、休日プログラムのヘッダーと動的セクション(オフセット)が表示されます。 彼らは本当に美しいドレスで私たちを必要としていますか?



ネタバレ:いいえ!*

(*-修正:はい、しかしそうではない)



エルフを切った


実行する正しいelfファイルを作成できる最小サイズを見てみましょう。 基礎として、私たちは今持っているものを取りますが、すべての有用な腸を捨てます。



simple.c:

 void _start(void) { asm( "xor %eax,%eax\n" "inc %eax\n" "int $0x80\n" ); }
      
      





それを集めましょう(スクリプトは過去のものです):

 cc -Wall -m32 -c simple.c -Os -nostartfiles -o simple-co && \ ld -melf_i386 -dynamic-linker /lib32/ld-linux.so.2 simple-co -o simple-c-orig && \ cp simple-c-orig simple-c && \ sstrip simple-c && \ cat simple-c | 7z a dummy -tGZip -mx=9 -si -so > simple-c.gz && \ cat unpack_header simple-c.gz > simple-c.sh && \ wc -c simple-c.sh && chmod +x simple-c.sh && \ ./simple-c.sh
      
      





結果のファイルと中間ファイルのサイズを確認すると、次のことがわかります。

  1. sstripが決定-ストリップされたsimple-cのサイズは、simple-c-origのサイズの(ほぼ)3倍小さい
  2. 圧縮はほとんど問題ではありません-解凍コードのある圧縮ファイルは、圧縮されていないファイルとほぼ同じくらいかかります
  3. (ldに-sオプションを追加すると、ストリップされた中間のバイナリのサイズを失ったり追加したりせずに、ストリップされていないファイルのサイズの約3分の1を獲得できます。


将来を見ると、これらのコメントは完全にやや役に立たないことに気付くことができますが、私たちは将来ではありません!



これで、readelfをバイナリに設定して、残っているもの、何に変わったのか、何になったのかを確認できます。

 $ readelf -a simple-c ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Intel 80386 Version: 0x1 Entry point address: 0x8048094 Start of program headers: 52 (bytes into file) Start of section headers: 0 (bytes into file) Flags: 0x0 Size of this header: 52 (bytes) Size of program headers: 32 (bytes) Number of program headers: 3 Size of section headers: 40 (bytes) Number of section headers: 0 Section header string table index: 0 There are no sections in this file. There are no sections in this file. Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x000000 0x08048000 0x08048000 0x0009e 0x0009e RE 0x1000 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4 PAX_FLAGS 0x000000 0x00000000 0x00000000 0x00000 0x00000 0x4 There is no dynamic section in this file. There are no relocations in this file. There are no unwind sections in this file. No version information found in this file.
      
      





だから、ストリップは良い仲間だと思われる、私たちのエルフの女の子のセクションは、これらの不要なセクションの見出しをすべて削除しました。 しかし、同時に、私たちの女性はまだ準備ができていません-彼女はまだブラジャー(GNU_STACKとPAX_FLAGSヘッダー)とパンティーを持っていますが、LOADヘッダーのFileSizが何らかの理由でファイル自体のサイズよりも小さいという事実に注意を払うと見つけることができますそれはco病者ではなく、単にファイルの最後にあるゴミであり、それをはぎ取る必要があります。

さらに、本当にうるさくて逆コンパイルしている場合(objdumpはプログラムではなくセクションヘッダーを読み取るため、objdump -Dはストライプされていないファイルでのみ動作します)、ここで生成したものは、最初の鮮度ではないことに注意する必要があります完全に有害なプロローグおよびエピローグ機能よりもわずかに多いソックス:

 00 55 push ebp 01 89e5 mov ebp, esp 03 31c0 xor eax, eax 05 40 inc eax 06 cd80 int 0x80 08 5d pop ebp 09 c3 ret
      
      





「有用な」コードの5バイトと5バイトの比率-役に立たないコードは、若い心を温めることもできません。 そして、私たちの若い心を温めるものは何ですか? 圧縮された恐竜と沼地の残骸を燃やします。 これらの非常に圧縮された沼地に、私の好奇心の強い読者が、あなた自身を浸すことをお勧めします。



指でエルフを作る


エルフを何もないところから組み立てるのは非常に簡単で、スタークラフトをオフにし、/ usr / include / elf.hファイルを開き、何も理解せず、elf.pdfファイルをグーグルで検索し、斜めに読んで、指先から引きちぎるだけです。以下:

 bits 32 ;   32-  org 0x00040000 ;        , ,       - $$ ;      ?    . ( ) ;  elf- db 0x7f, 'ELF' ; magic   ,    ,   ELF db 1 ; EI_CLASS = ELFCLASS32 db 1 ; EI_DATA ELFDATA2LSB db 1 ; EI_VERSION = EV_CURRENT times 9 db 0 ; 9  ,          dw 2 ; e_type = ET_EXEC --   dw 3 ; e_machine = EM_386 dd 1 ; e_version = EV_CURRENT dd _start ; e_entry --   ,       dd phdrs - $$ ; e_phoff --    ,    program headers dd 0 ; e_shoff -- --//-- section headers,   ,  , ,  0 dd 0 ; e_flags --      dw ehsize ; e_ehsize --  ELF- (52 ) dw phsize ; e_phentsize --   program header (32 ) dw 1 ; e_phnum --   dw 0 ; e_shentsize --  section header dw 0 ; e_shnum --   () dw 0 ; e_shstrndx -- -    ,    ehsize equ ($-$$) ; $       (+ org),   ehsize    elf- phdrs: ;  program header dd 1 ; p_type = PT_LOAD --   "     , " dd 0 ; p_offset --    ,   dd $$ ; p_vaddr --   ,   dd $$ ; p_paddr --  , - - ,    ,           dd file_size ; p_filesz --   ,      dd file_size ; p_memsz --     .  ,  e_filesz,    .   --      6 . . !!11   ,  ,     .             . dd 7 ; p_flags (=PF_RWX) --     ,   . dd 0x1000 ; p_align -- ,    ,     . 0x1000     phsize equ ($-phdrs) ;    program header _start: ;  xor eax, eax ; eax = 0 inc eax ; eax = 1 (exit syscall) int 0x80 ;  syscall file_size equ ($-$$) ;       
      
      





(実際、この失礼な、しかし少し風変わりな、asmファイルをコメントアウトする代わりに、私の愛する恋人たちに、抱きしめて大きなELF形式の図を描いてほしいと思ったのですが、それで記事があと2、3延期されることに気付きました。年)



追加のヘッダーなしで、「フラット」バイナリのコンパイルディレクティブを使用して、nasmでこのファイルをコンパイルする必要があります。

 $ nasm -f bin simple.asm -o simple-asm
      
      





この行は、89バイトのsimple-asmファイルを作成します。これは、前に作成した206バイトのモンスターに完全に機能する類似物です。 これらの206バイトが、実際には元の圧縮されていない縞模様の狂気の657バイトであるという事実は言うまでもありません。

できる
 chmod +x simple-asm
      
      



そして、それが実際に有効であり、開始することさえ確認してください。 89バイトは制限からかけ離れていると言えます。このファイルを約2倍絞ることができます。エルフヘッダーを唯一のプログラムヘッダーに配置すると、超有効なエルフだけでなく、起動してサイズを小さくすることができます。 elfヘッダー自体よりも(それからの最後の6バイトは、ゼロがあれば、自動的にゼロになります) [1] 。 Linuxには、素晴らしいファイル/ dev / fb0と/ dev / dspがあり、128-256-512バイトのDOSスタイルでイントラを実行できることを思いがけず思い浮かびます。 ただし、ここではこれを行いません。これは、記号の別の山に関するトピックです。

そして、ここでOpenGLを接続する方法を見つけ出します。



悪魔のリンク


OpenGLコンテキストを作成するために、前の部分からおそらく漠然と覚えているように、libSDL.soのように動的に接続されたSDLライブラリを使用しました。 もちろん、それに加えて、libGL.soライブラリの形式で提供されるOpenGL自体も必要です。

彼らが言うように、自家製のバイナリを何かに動的にリンクできるようにすることを学ぶ必要があることを理解することは難しくありません。

低レベルのLinuxでの動的リンクのメカニズムは非常に面白いです。 バイナリをロードすると、システムはインタープリターファイルの名前を示すPT_INTERPタイプのプログラムヘッダーを検出します。 「はい、あなたはこのダイナミックリンクでロバに行き、あなたがとても賢いなら自分でそれを整理します」とシステムは言い、バイナリをロードし続ける代わりに、インタプリタをロードして制御を移します。

インタプリタはすでにアプリケーションをさらにロードしています-何も起こらなかったように、プロセスにPT_LOADセクションを独立してロードし、最も重要なことには、動的リンクに必要なすべての説明へのリンクを含むPT_DYNAMICを読み込みます-必要なライブラリ、関数の名前、そして重要なことに、それらをロードする方法。 PT_DYNAMICによって参照されるデータ形式は、それ自体非常に単純です。d_tagとd_valのダブルワードのペアのテーブルです。d_tagはパラメーターコードで、d_valはその値です。それについて)。

どのパラメーターと値を指定する必要がありますか? 元のファイルのreadelfダンプに戻って、すべてを見てみましょう。 行「オフセット...の動的セクション」の後。



怖い



私たちは、それらの3分の1はまったく必要ないと考えて安心しています。 興奮は、しかし、後退しません-残りのフィールドはまだひどいです。 ただし、その意味を詳細には説明しません-一部は自分で覚えていないからです(かなり前に取り上げました)が、覚えていることは忘れたいです。

したがって、読者の皆さん、私は、味のコメントの薄い層がきちんと散らばった既製のレシピをもたらします。 健康に使用してください。



このピースは、phsizeの計算直後にphdrsに追加されます。

 dd 2 ; p_type = PT_DYNAMIC dd dynamic - $$ ; p_offset dd dynamic ; p_vaddr dd dynamic ; p_paddr dd dynamic_size ; p_filesz dd dynamic_size ; p_memsz dd 6 ; p_flags = PF_RW dd 4 ; p_align dd 3 ; p_type = PT_INTERP dd interp - $$ ; p_offset dd interp ; p_vaddr dd interp ; p_paddr dd interp_size ; p_filesz dd interp_size ; p_memsz dd 4 ; p_flags = PF_R dd 1 ; p_align ;   PT_DYNAMIC ;     dynamic: dd 1, st_libdl_name ; DT_NEEDED --     ,   st_libdl_name (   ) ;  ,    ,       ;dd 1, st_libSDL_name ;dd 1, st_libGL_name dd 4, dt_hash ; DT_HASH --     dd 5, dt_strtab ; DT_STRTAB --    .            dd 6, dt_symtab ; DT_SYMTAB --     dd 10, dt_strtab_size ; DT_STRSZ --    dd 11, dt_symtab_size ; DT_SYMENT --    dd 17, dt_rel ; DT_REL --     dd 18, dt_rel_size; DT_RELSZ --    dd 19, 8 ; DT_RELENT --       dd 0, 0 ; DT_NULL --    DT_DYNAMIC dynamic_size equ $ - dynamic ;   DT_HASH ;     -      ;    ,         ;     dt_hash: dd 1, 3, 0, 0, 0, 0 ;   DT_SYMTAB ;      ,       dt_symtab: ; 0 --    (?!) dd 0, 0, 0 dw 0, 0 ; SHN_UNDEF ; 1 'dlopen' dd st_dlopen_name, 0, 0 dw 0x12 ; = ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), ..,  ,   --   dw 0 ; SHN_UNDEF ,      ,      ; 2 'dlsym' dd st_dlsym_name, 0, 0 dw 0x12, 0 ; --//-- dt_symtab_size equ $ - dt_symtab ;   DT_REL ;  . ,          dt_rel: dd rel_dlopen ; ,   dd 0x0101 ; ELF32_R_INFO(1,R_386_32) : dt_symtab[1] ('dlopen'),  =    + r_addend(=0  ) dd rel_dlsym ; --//-- dd 0x0201 ; ELF32_R_INFO(2,R_386_32) : dt_symtab[2] ('dlsym'), --//-- dt_rel_size equ $ - dt_rel ;    -- ,       ;   DT_STRTAB ;  .    ,   PT_DYNAMIC --      dt_strtab: st_libdl_name equ $ - dt_strtab ;       db 'libdl.so.2', 0 ;   -- - st_dlopen_name equ $ - dt_strtab db 'dlopen', 0 st_dlsym_name equ $ - dt_strtab db 'dlsym', 0 dt_strtab_size equ $ - dt_strtab ;       interp: db '/lib/ld-linux.so.2', 0 interp_size equ $ - interp
      
      





さらに、以下を修正する必要があります。

  1. 明らかにe_phnumを3に変更します
  2. ファイルの最後に追加します

     ; BSS-,      absolute $ bss: ;      rel_dlopen: resd 1 rel_dlsym: resd 1 mem_size equ ($-$$)
          
          



  3. mem_sizeに設定されたPT_LOADヘッダーp_memsz内




これで、人工エルフは動的にリンクできるようになりました。 これをチェックしてください。

これは単なるテストではなく、潜在的なイントラなので、ファイルの名前をintro.asmに変更します。 それを集めましょう:

 $ nasm -f bin intro.asm -o intro && chmod +x intro
      
      





そして、straceを実行して、彼が実際にあらゆる種類の読み取りを試みていることを確認します。

 $ strace ./intro execve("./intro", ["./intro"], [/* 67 vars */]) = 0 [ Process PID=24135 runs in 32 bit mode. ] ... open("/lib32/libdl.so.2", O_RDONLY) = 3 ...
      
      





これで、ファイルサイズ-368の非圧縮バイトを確認できます。 通常の方法(cc + ld)で、同様の非圧縮ファイルがすぐに4キロバイトに膨張することを個別に確認できます。

圧縮ファイルの重量はいくらですか?

 nasm -f bin intro.asm -o intro && chmod +x intro && \ cat intro | 7z a dummy -tGZip -mx=9 -si -so > intro.gz && \ cat unpack_header intro.gz > intro.sh && \ wc -c intro.sh && chmod +x intro.sh && \ ./intro.sh
      
      





254バイト。

しかし、彼はまだ何もしていません。



彼にやらせてください!


さて、dlopenとdlsymを自由に使えるようになったら、libSDLとlibGLからいくつかの関数をロードして、そのようなものを取得することができます。

私たちは特に自慢せず、お互いにやったことをすべてアセンブラーに移植します。

 ;    ,     libs_to_dl: st_libSDL_name equ $ - dt_strtab db 'libSDL-1.2.so.0', 0 ;  -  ,      db 'SDL_Init', 0 db 'SDL_SetVideoMode', 0 db 'SDL_PollEvent', 0 db 'SDL_GetTicks', 0 db 'SDL_ShowCursor', 0 db 'SDL_GL_SwapBuffers', 0 db 'SDL_Quit', 0 db 0 ;    =   st_libGL_name equ $ - dt_strtab db 'libGL.so.1', 0 db 'glViewport', 0 db 'glCreateShader', 0 db 'glShaderSource', 0 db 'glCompileShader', 0 db 'glCreateProgram', 0 db 'glAttachShader', 0 db 'glLinkProgram', 0 db 'glUseProgram', 0 db 'glRectf', 0 db 0, 0 ;    =   _start: ;  mov ebp, bss ;  ebp     bss --  , ! ; - ,   %define BSSADDR(a) ebp + ((a) - bss) %define F(f) [ebp + ((f) - bss)] ;    mov esi, libs_to_dl+1 ; +1, .. ld_load ,          lea edi, [BSSADDR(libs_syms)] ; edi =  ,       ld_load: dec esi ;          1,    ;    dlopen,     push 1 ; RTLD_LAZY push esi ;    call F(rel_dlopen) ; eax = dlopen([esi], 1) ;  ,    <s>   </s>     mov ebx, eax ;  ,  dlopen  ,  ebx ;    0 ld_skip_to_zero: lodsb test al, al jnz ld_skip_to_zero ;    \0     lodsb test al, al jz ld_second_zero dec esi ;    1  push esi ;      push ebx ;   dlopen     call F(rel_dlsym) ; eax = dlsym([ebx], [esi]) stosd ;  eax (   )  [edi], edi += 4 jmp ld_skip_to_zero ;     ld_second_zero: ;    ,   - ! lodsb test al, al jnz ld_load ;     ! ;   ! xor eax, eax ; eax = 0 inc eax ; ex = 1 (exit syscall) int 0x80 ;  syscall file_size equ ($-$$) ;        ; BSS-,      absolute $ bss: ;      libdl_syms: rel_dlopen: resd 1 rel_dlsym: resd 1 libs_syms: SDL_Init: resd 1 SDL_SetVideoMode: resd 1 SDL_PollEvent: resd 1 SDL_GetTicks: resd 1 SDL_ShowCursor: resd 1 SDL_GL_SwapBuffers: resd 1 SDL_Quit: resd 1 glViewport: resd 1 glCreateShader: resd 1 glShaderSource: resd 1 glCompileShader: resd 1 glCreateProgram: resd 1 glAttachShader: resd 1 glLinkProgram: resd 1 glUseProgram: resd 1 glRectf: resd 1 mem_size equ ($-$$)
      
      





_start自体を含む、_startの直後に発生するすべての代わりに、このピースを挿入する必要があります。

コンパイルし、サイズが455バイトのファイルを取得して実行し、クラッシュしないことを確認します。 クラッシュした場合、libSDLとlibGLのDT_NEEDED行のコメントを解除して、何が起こるかを確認しようとします。



すべてうまくいけば、先に進み、最後にシェーダーでOpenGLを初期化できます。 (コメントに書かれていることを除いて)特に注意が必要なことはありません。アセンブラーで以前にその場で行ったことを繰り返します。

 ; nasm -f bin intro.asm -o intro && chmod +x intro && \ ; cat intro | 7z a dummy -tGZip -mx=9 -si -so > intro.gz && \ ; cat unpack_header intro.gz > intro.sh && \ ; wc -c intro.sh && chmod +x intro.sh && \ ; ./intro.sh %define WIDTH 640 %define HEIGHT 360 %define FULLSCREEN 0 ;%define FULLSCREEN 0x80000000 bits 32 ;   32-  org 0x00040000 ;        , ,       - $$ ;      ?    . ( ) ;  elf- db 0x7f, 'ELF' ; magic   ,    ,   ELF db 1 ; EI_CLASS = ELFCLASS32 db 1 ; EI_DATA ELFDATA2LSB db 1 ; EI_VERSION = EV_CURRENT times 9 db 0 ; 9  ,          dw 2 ; e_type = ET_EXEC --   dw 3 ; e_machine = EM_386 dd 1 ; e_version = EV_CURRENT dd _start ; e_entry --   ,       dd phdrs - $$ ; e_phoff --    ,    program headers dd 0 ; e_shoff -- --//-- section headers,   ,  , ,  0 dd 0 ; e_flags --      dw ehsize ; e_ehsize --  ELF- (52 ) dw phsize ; e_phentsize --   program header (32 ) dw 3 ; e_phnum --   dw 0 ; e_shentsize --  section header dw 0 ; e_shnum --   () dw 0 ; e_shstrndx -- -    ,    ehsize equ ($-$$) ; $       (+ org),   ehsize    elf- phdrs: ;  program header dd 1 ; p_type = PT_LOAD --   "     , " dd 0 ; p_offset --    ,   dd $$ ; p_vaddr --   ,   dd $$ ; p_paddr --  , - - ,    ,           dd file_size ; p_filesz --   ,      dd mem_size ; p_memsz --     .  ,  e_filesz,    .   --      6 . . !!11   ,  ,     .             . dd 7 ; p_flags (=PF_RWX) --     ,   . dd 0x1000 ; p_align -- ,    ,     . 0x1000     phsize equ ($-phdrs) ;    program header dd 2 ; p_type = PT_DYNAMIC dd dynamic - $$ ; p_offset dd dynamic ; p_vaddr dd dynamic ; p_paddr dd dynamic_size ; p_filesz dd dynamic_size ; p_memsz dd 6 ; p_flags = PF_RW dd 4 ; p_align dd 3 ; p_type = PT_INTERP dd interp - $$ ; p_offset dd interp ; p_vaddr dd interp ; p_paddr dd interp_size ; p_filesz dd interp_size ; p_memsz dd 4 ; p_flags = PF_R dd 1 ; p_align ;   PT_DYNAMIC ;     dynamic: dd 1, st_libdl_name ; DT_NEEDED --     ,   st_libdl_name (   ) ;  ,    ,       ;dd 1, st_libSDL_name ;dd 1, st_libGL_name dd 4, dt_hash ; DT_HASH --     dd 5, dt_strtab ; DT_STRTAB --    .            dd 6, dt_symtab ; DT_SYMTAB --     dd 10, dt_strtab_size ; DT_STRSZ --    dd 11, 16 ; DT_SYMENT --       dd 17, dt_rel ; DT_REL --     dd 18, dt_rel_size; DT_RELSZ --    dd 19, 8 ; DT_RELENT --       dd 0, 0 ; DT_NULL --    DT_DYNAMIC dynamic_size equ $ - dynamic ;   DT_HASH ;     -      ;    ,         ;     dt_hash: dd 1, 3, 0, 0, 0, 0 ;   DT_SYMTAB ;      ,       dt_symtab: ; 1 --    (?!) dd 0, 0, 0 dw 0, 0 ; SHN_UNDEF ; 2 'dlopen' dd st_dlopen_name, 0, 0 dw 0x12 ; = ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), ..,  ,   --   dw 0 ; SHN_UNDEF ,      ,      ; 3 'dlsym' dd st_dlsym_name, 0, 0 dw 0x12, 0 ; --//-- ;   DT_REL ;  . ,          dt_rel: dd rel_dlopen ; ,   dd 0x0101 ; ELF32_R_INFO(1,R_386_32) : dt_symtab[1] ('dlopen'),  =    + r_addend(=0  ) dd rel_dlsym ; --//-- dd 0x0201 ; ELF32_R_INFO(2,R_386_32) : dt_symtab[2] ('dlsym'), --//-- dt_rel_size equ $ - dt_rel ;    -- ,       ;       interp: db '/lib/ld-linux.so.2', 0 interp_size equ $ - interp ;   DT_STRTAB ;  .    ,   PT_DYNAMIC --      dt_strtab: st_libdl_name equ $ - dt_strtab ;       db 'libdl.so.2', 0 ;   -- - st_dlopen_name equ $ - dt_strtab db 'dlopen', 0 st_dlsym_name equ $ - dt_strtab db 'dlsym', 0 dt_strtab_size equ $ - dt_strtab ;    ,     libs_to_dl: st_libSDL_name equ $ - dt_strtab db 'libSDL-1.2.so.0', 0 ;  -  ,      db 'SDL_Init', 0 db 'SDL_SetVideoMode', 0 db 'SDL_PollEvent', 0 db 'SDL_GetTicks', 0 db 'SDL_ShowCursor', 0 db 'SDL_GL_SwapBuffers', 0 db 'SDL_Quit', 0 db 0 ;    =   st_libGL_name equ $ - dt_strtab db 'libGL.so.1', 0 db 'glViewport', 0 db 'glCreateShader', 0 db 'glShaderSource', 0 db 'glCompileShader', 0 db 'glCreateProgram', 0 db 'glAttachShader', 0 db 'glLinkProgram', 0 db 'glUseProgram', 0 db 'glRectf', 0 db 0, 0 ;    =   shader_vtx: db 'varying vec4 p;' db 'void main(){gl_Position=p=gl_Vertex;pz=length(p.xy);}' db 0 shader_frg: db 'varying vec4 p;' db 'void main(){' db 'float ' db 'z=1./length(p.xy),' db 'a=atan(px,py)+sin(p.z+z);' db 'gl_FragColor=' db '2.*abs(.2*sin(pz*3.+z*3.)+sin(p.z+a*4.)*p.xyxx*sin(vec4(z,a,a,a)))+(z-1.)*.1;' db '}', 0 _start: ;  mov ebp, bss ;  ebp     bss --  , ! ; - ,   %define BSSADDR(a) ebp + ((a) - bss) %define F(f) [ebp + ((f) - bss)] ;    mov esi, libs_to_dl+1 ; +1, .. ld_load ,          lea edi, [BSSADDR(libs_syms)] ; edi =  ,       ld_load: dec esi ;          1,    ;    dlopen,     push 1 ; RTLD_LAZY push esi ;    call F(rel_dlopen) ; eax = dlopen([esi], 1) ;  ,    <s>   </s>     mov ebx, eax ;  ,  dlopen  ,  ebx ;    0 ld_skip_to_zero: lodsb test al, al jnz ld_skip_to_zero ;    \0     lodsb test al, al jz ld_second_zero dec esi ;    1  push esi ;      push ebx ;   dlopen     call F(rel_dlsym) ; eax = dlsym([ebx], [esi]) stosd ;  eax (   )  [edi], edi += 4 jmp ld_skip_to_zero ;     ld_second_zero: ;    ,   - ! lodsb test al, al jnz ld_load ;    ! push 0x21 ; SDL_INIT_ TIMER | VIDEO call F(SDL_Init) ; SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO); push 2 | FULLSCREEN ; SDL_OPENGL push 32 ; 32    push HEIGHT push WIDTH call F(SDL_SetVideoMode) ; SDL_SetVideoMode(WIDTH, HEIGHT, 32, SDL_OPENGL|FULLSCREEN); ; WxH    ! cdecl ftw! push 0 push 0 call F(glViewport) ; glViewport(0, 0, WIDTH, HEIGHT); call F(SDL_ShowCursor) ; SDL_ShowCursor(0); ;   call F(glCreateProgram) ; eax = glCreateProgram(); mov edi, eax ; edi = program_id push 0x8b31 pop esi ; esi = GL_VERTEX_SHADER ;     4    ebp  temp  --       dlopen,   mov dword [ebp], shader_vtx push esi call F(glCreateShader) ; eax = glCreateShader(GL_VERTEX_SHADER); mov ebx, eax push 0 push ebp push 1 push eax call F(glShaderSource) ; glShaderSource(shader_id, 1, &shader_vtx, 0); push ebx ;  nVidia  ,     call F(glCompileShader) ; glCompileShader(shader_id); push ebx ;     ! push edi call F(glAttachShader) ; glAttachShader(program_id, shader_id); dec esi ; esi = GL_FRAGMENT_SHADER mov dword [ebp], shader_frg ;   ,   =  ! push esi call F(glCreateShader) mov ebx, eax push 0 push ebp push 1 push eax call F(glShaderSource) push ebx call F(glCompileShader) push ebx push edi call F(glAttachShader) push edi call F(glLinkProgram) ; glLinkProgram(program_id); call F(glUseProgram) ; glUseProgram(program_id); mainloop: call F(SDL_GetTicks) ; eax == SDL_GetTicks(); --    mov [ebp], eax fninit ;    FPU,        fild dword [ebp] ; st(0) = eax == time  , st(1) = 1000 push 400 ;    ,   ,    fild dword [esp] ; st(0) = 1000 fdiv ; st(0) /= 1000 =    fld1 ; st(0) = 1, st(1) =    faddp st1 ; st(0) =    + 1 fst dword [ebp] mov eax, [ebp] ; eax = (float-ieee)t   fchs ; st(0) = -st(0) fstp dword [ebp] mov ebx, [ebp] ; ebx = -(float-ieee)t   push ebx push ebx push eax push eax call F(glRectf) ; glRectf(-t,-t,t,t) times 5 pop eax ; ,  ,    , ..          call F(SDL_GL_SwapBuffers) lea edx, [BSSADDR(SDL_Event)] ;     SDL_Event push edx call F(SDL_PollEvent) ; SDL_PollEvent(&SDL_Event); pop edx ;  edx cmp byte [edx], 2 ; SDL_Event.type != SDL_KEYDOWN jnz mainloop call F(SDL_Quit) ;      ;   ! xor eax, eax ; eax = 0 inc eax ; ex = 1 (exit syscall) int 0x80 ;  syscall file_size equ ($-$$) ;        ; BSS-,      absolute $ bss: ;      libdl_syms: rel_dlopen: resd 1 rel_dlsym: resd 1 libs_syms: SDL_Init: resd 1 SDL_SetVideoMode: resd 1 SDL_PollEvent: resd 1 SDL_GetTicks: resd 1 SDL_ShowCursor: resd 1 SDL_GL_SwapBuffers: resd 1 SDL_Quit: resd 1 glViewport: resd 1 glCreateShader: resd 1 glShaderSource: resd 1 glCompileShader: resd 1 glCreateProgram: resd 1 glAttachShader: resd 1 glLinkProgram: resd 1 glUseProgram: resd 1 glRectf: resd 1 SDL_Event: resb 24 mem_size equ ($-$$)
      
      





子猫よ、最後に1024にほとんど収まらない750バイトを入力します。この結果を改善することは可能ですか?

もちろん次のことができます。

  1. 多くの構造は、他の構造が終わるものと同じものから始まります
  2. 同様のデータを並べて配置すると便利です(ヘッダーが緩んでいる、行が揃っている、x86命令をインターリーブできない)
  3. 組織変更
  4. 投げ捨てる-たとえば、SDL_ShowCursorですべてをコメントアウトします


圧縮ファイルのサイズは、非圧縮ファイルのサイズに応じて単調にはほど遠いことを覚えておく価値があります。たとえば、espを追加する前に5ポップeaxのサイズが顕著に20倍

になります。不潔なほうきでコメントアウトすると、最後の3つの不要なelfヘッダーフィールド(e_shentsizeとそれに続く2つのガチョウ)は、phdrsとdynamic、dt_hash、dt_symtabの間のゼロと他の同一データを削除します。

合計:718バイト。

あなたとの関係はわかりませんが、私の手はすでにかゆみを感じています。 306バイトもあります(シェーダーを絶滅したトンネルに完全に置き換えることができるという事実を考慮すると、さらに大きくなります)!

このような想像を絶するほど大きなキャンバスで何ができるでしょうか?



たとえば、そのようなもの











(慎重に、強力なグラフィックカードが必要です):

 shader_vtx: db 'varying vec4 p,v;' db 'void main()' db '{' db 'gl_Position=gl_Vertex;' db 'p=vec4(mat3(cos(length(gl_Vertex.xy)),0.,sin(length(gl_Vertex.xy)),0.,1.,0.,-sin(length(gl_Vertex.xy)),0.,cos(length(gl_Vertex.xy)))*vec3(gl_Vertex.xy*.1,-.9),length(gl_Vertex.xy));' db 'v=vec4(mat3(cos(length(gl_Vertex.xy)),0.,sin(length(gl_Vertex.xy)),0.,1.,0.,-sin(length(gl_Vertex.xy)),0.,cos(length(gl_Vertex.xy)))*vec3(gl_Vertex.xy*.1,.1),length(gl_Vertex.xy));' db '}' db 0 shader_frg: db 'varying vec4 p,v;' ;db 'float mx(vec3 a){return max(ax,max(ay,az));}' db 'float mn(vec3 a){return min(ax,min(ay,az));}' db 'float F(vec3 a){return min(mn(vec3(1.)-abs(a)),-mn(abs(mod(a+vec3(.1),vec3(.4))-vec3(.2))-.15));}' ;db 'float F(vec3 a){return min(mn(vec3(1.)-abs(a)),length(mod(a,vec3(.4))-vec3(.2))-.06);}' db 'vec3 n(vec3 a){' db 'vec3 e=vec3(.0001,.0,.0);' db 'return normalize(vec3(F(a)-F(a+e.xyy),F(a)-F(a+e.yxy),F(a)-F(a+e.yyx)));' db '}' db 'vec4 tr(vec3 E,vec3 D){' db 'D=normalize(D);' db 'float L=.01;' db 'int i=0;' db 'for(i;i<512;++i){' db 'float d=F(E+D*L);' db 'if(d<.0001)break;' db 'L+=d;' db '}' ;db 'return vec2(L,float(i)/512.);' db 'return vec4(E+D*L,float(i)/512.);' db '}' db 'float I(vec3 a){' db 'vec3 l=vec3(sin(pw*1.3),cos(pw*4.2),sin(pw*3.2))*.9,la=la;' db 'return length(tr(a,la).xyz-a)*dot(n(a),-normalize(la))/dot(la,la)+.01;' ;db 'return tr(a,-lv).x*F(a+lv)/dot(lv,lv)+.01;' db '}' db 'void main(){' db 'vec4 t=tr(p.xyz,v.xyz);' db 'gl_FragColor=I(t.xyz)*(abs(t)+vec4(tw*5.));' ;db 'vec2 t=tr(p.xyz,v.xyz);' ;db 'vec3 q=p.xyz+normalize(v.xyz)*tx;' ;db 'gl_FragColor=I(q)+vec4(ty);' db '}' db 0
      
      







またはこれ:





 shader_vtx: db 'varying vec4 p,v;' db 'void main()' db '{' db 'gl_Position=gl_Vertex;' db 'p=vec4(mat3(cos(length(gl_Vertex.xy)),0.,sin(length(gl_Vertex.xy)),0.,1.,0.,-sin(length(gl_Vertex.xy)),0.,cos(length(gl_Vertex.xy)))*vec3(gl_Vertex.xy*.1,-.9),length(gl_Vertex.xy));' db 'v=vec4(mat3(cos(length(gl_Vertex.xy)),0.,sin(length(gl_Vertex.xy)),0.,1.,0.,-sin(length(gl_Vertex.xy)),0.,cos(length(gl_Vertex.xy)))*vec3(gl_Vertex.xy*.1,.1),length(gl_Vertex.xy));' db '}' db 0 shader_frg: db 'varying vec4 p,v;' db 'float mn(vec3 a){return min(ax,min(ay,az));}' db 'float F(vec3 a){return min(mn(vec3(1.)-abs(a)),length(mod(a,vec3(.4))-vec3(.2))-.06);}' db 'vec3 n(vec3 a){' db 'vec3 e=vec3(.0001,.0,.0);' db 'return normalize(vec3(F(a)-F(a+e.xyy),F(a)-F(a+e.yxy),F(a)-F(a+e.yyx)));' db '}' db 'vec3 tr(vec3 E,vec3 D){' db 'D=normalize(D);' db 'float L=.01;' db 'int i=0;' db 'for(i;i<512;++i){' db 'float d=F(E+D*L);' db 'if(d<.001)break;' db 'L+=d;' db '}' db 'return E+D*L;' db '}' db 'vec3 I(vec3 a,vec3 l,vec3 c){' db 'return c*(clamp(length(tr(a,la)-a),0.,length(la))*dot(n(a),normalize(al))/dot(la,la));' db '}' db 'void main(){' db 'vec3 t=tr(p.xyz,v.xyz);' db 'gl_FragColor=vec4(' db 'I(t,vec3(sin(pw*1.3),cos(pw*4.2),sin(pw*3.2))*.7,vec3(.9,.6,.2))+' db 'I(t,vec3(sin(pw*3.2),sin(pw*4.2),sin(pw*1.3))*.7,vec3(.0,.3,.5)),1.);' db '}' db 0
      
      





なぜこれらのシェーダーはそのような画像を与えるのですか?来年3月に投稿頻度の良い伝統に従って、これについてお伝えします!せっかちで独立したキーワード:レイマーチング距離フィールド(この男は多くの情報を持っています)。



エピローグ


このテキストには誤り、準最適性、simply慢な嘘(ここで自分の信頼を悪用した回数を数えます)がたくさんあるという事実にもかかわらず、私はそれが有用であることが判明し、少なくとも誰かが別のスタートアップを作らないことを望みますが、代わりに本当に複雑で、面白くて価値のあるものを作成します。



そのような写真では、クラスメートを恥ずかしくはないはずであり、一般的にはかかとや他のファンの悲鳴のうなり声が聞こえるはずですが、まだ開発の余地があり、これは終わりではありません、あなたが行くところ、それは終わりではありません!

次回、Cプログラミング言語でスウィンギングベースを何からも引き出してダンスフロアを爆破する方法についてのストーリーを待っているとき。

10月にまた会いましょう!



All Articles