Jak zmniejszyć rozmiar EXE x86 ASM skompilowanego z FASM?

14

Jako ćwiczenie stworzyłem proste rozwiązanie dla tego wyzwania, w języku asemblera x86. Korzystam z FASM w systemie Windows. Oto mój kod źródłowy:

format PE console
entry start

include 'WIN32A.inc'

section '.text' code executable
start:
    push    char            ; Start at 'A'
    call    [printf]        ; Print the current letter 4 times
    call    [printf]
    call    [printf]
    call    [printf]
    inc     [char]          ; Increment the letter
    cmp     [char], 'Z'     ; Compare to 'Z'
    jle     start           ; char <= 'Z' --> goto start

section 'r.data' data readable writeable
    char    db  'A', 10, 0  ; Stores the current letter

section '.idata' data readable import
    library  msvcrt,   'msvcrt.dll'
    import   msvcrt, printf, 'printf'

Kiedy to kompiluję, otrzymuję plik wykonywalny większy niż się spodziewałem. Oto zrzut heksowy:

https://pastebin.com/W5sUTvTe

Zauważyłem, że między sekcją kodu a sekcjami importu danych i bibliotek jest dużo pustej przestrzeni, a także komunikat „Nie można uruchomić tego programu w trybie DOS” w kodzie. Jak mogę złożyć kod źródłowy w mały plik odpowiedni dla Code Golf?

Na marginesie mile widziane są sugestie dotyczące lepszych sposobów drukowania stdoutbez importowania msvcrti dzwonienia printf.

vasilescur
źródło
@iBug Przykro mi to słyszeć. Czy możesz mi zaproponować bardziej odpowiednie miejsce do zapytania?
vasilescur
12
@iBug Wskazówki Pytania dotyczące gry w golfa w określonych przypadkach zdecydowanie nie są tutaj nie na temat.
AdmBorkBork,
12
Odpowiednie meta
AdmBorkBork
1
Musi to być: start: push char Lb: call [printf] call [printf] call [printf] call [printf] inc [char] cmp [char], 'Z' jle Lb, ponieważ jeśli nie, może zużyć stos ; trzeba sprawdzić, czy każde wezwanie do printf należy dodać instrukcję, która dostosowuje esp
RosLuP
1
zamiast printf, możesz WriteFile (stdout), nie wymagając importu innego niż kernel32 (który jest domyślnie obecny, wystarczy określić adres)
peter ferrie

Odpowiedzi:

2

Dość ogólna wskazówka, ale

Użyj formatu pliku COM zamiast PE EXE.

PE EXE ma kilka wad, które sprawiają, że format ten jest praktycznie bezużyteczny w golfowym kodzie. Pierwszy to wyrównanie obrazu (system Windows nie uruchomi pliku EXE, jeśli nie jest poprawnie wyrównany), a drugi to rozmiar nagłówka. Istnieje kilka czynników, które nie są tak ważne (dzielenie pliku wykonywalnego na sekcje).

Zalety korzystania z formatu pliku COM (który jest prawie równoważny płaskiemu plikowi binarnemu) to:

  • Zero kodu nagłówka, plik nie jest podzielony na sekcje
  • Brak wyrównywania obrazu (więc rozmiar obrazu może nie być podzielny przez ściśle określoną potęgę dwóch, ale musi być mniejszy niż 65 K. Nie zmienia to jednak wiele, ponieważ jeśli przesłanie jest większe niż 65 K. coś źle).
  • Nie możesz używać bibliotek zewnętrznych - to tak naprawdę plus, ponieważ bez wątpienia masz inny sposób wykonywania operacji we / wy. To miejsce, gdzie przerwań BIOS się przydać.
  • Masz bezpośrednią kontrolę nad pamięcią i urządzeniami podłączonymi do systemu, dlatego nie ma stronicowania, żadnych naruszeń dostępu, żadnej ochrony pamięci, żadnej współbieżności itd. Te funkcje ułatwiają grę w naprawdę kreatywne programy.

Zmodyfikowałem twój kod, aby działał jako płaski plik binarny. To bardzo proste:

ORG 100H

MOV DX, P
MOV AH, 9

L:
    INT 21H
    INT 21H
    INT 21H
    INT 21H

    INC BYTE [P]
    CMP BYTE [P], 'Z'
    JLE L

MOV AX, 4C00h
INT 21h

P DB "A", 10, "$"

Wyjściowy plik binarny ma tylko 32 bajty. Wierzę, że można jeszcze bardziej zmniejszyć rozmiar, ale to tylko punkt wyjścia.

Zbierz z nasm -fbin file.asm -o file.com. Uwaga: ten przykład został stworzony dla NASM, ale możesz go swobodnie przetłumaczyć na FASM i będzie działał bezbłędnie.

Krzysztof Szewczyk
źródło
Nie mogę uwierzyć, że odpowiedziałem na to pytanie i wróciłem do niego z Google
Krzysztof Szewczyk,