Как уменьшить размер EXE-файла x86 ASM, скомпилированного с FASM?

14

В качестве упражнения я создал простое решение этой проблемы на языке ассемблера x86. Я запускаю это с FASM на Windows. Вот мой исходный код:

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'

Когда я компилирую это, я получаю исполняемый файл больше, чем я ожидал. Вот hexdump:

https://pastebin.com/W5sUTvTe

Я заметил, что между разделом кода и разделами импорта данных и библиотек есть много пустого пространства, а также встроенное в код сообщение «Эта программа не может быть запущена в режиме DOS». Как собрать исходный код в небольшой файл, подходящий для Code Golf?

В качестве примечания приветствуются предложения по улучшению способов печати stdoutбез импорта msvcrtи вызова printf.

vasilescur
источник
@iBug Мне жаль это слышать. Не могли бы вы предложить более подходящее место для меня, чтобы спросить?
vasilescur
12
@iBug Советы, вопросы с просьбой о помощи в гольф в определенных случаях, совершенно определенно не являются не по теме здесь.
AdmBorkBork
1
Это должно быть: start: push char Lb: call [printf] вызов [printf] вызов [printf] вызов [printf] inc [char] cmp [char], 'Z' jle Lb, потому что если нет, то может потреблять стек ; нужно посмотреть, нужно ли каждый вызов printf добавлять инструкцию, которая корректирует esp
RosLuP
1
вместо printf вы можете использовать WriteFile (stdout), не требующий импорта, кроме kernel32 (который присутствует по умолчанию, вам просто нужно определить адрес)
peter ferrie

Ответы:

2

Совсем немного общего совета, но

Используйте формат файла COM вместо PE EXE.

PE EXE имеет несколько недостатков, делающих формат практически бесполезным в коде-гольфе. Первый - выравнивание изображения (Windows не запускает EXE-файл, если он не выровнен должным образом), а второй - размер заголовка. Есть несколько факторов, которые не так важны (деление исполняемого файла на разделы).

Преимущества использования формата файла COM (который в значительной степени эквивалентен плоскому двоичному файлу):

  • Нулевой код заголовка, файл не разделен на разделы
  • Нет выравнивания изображения (поэтому размер изображения может не делиться на строго определенную степень двойки, но он должен быть меньше 65K. Хотя это не сильно изменится, потому что если ваше представление больше 65K, вы делаете что-то не так).
  • Вы не можете использовать внешние библиотеки - это на самом деле плюс, потому что у вас, без сомнения, есть другой способ выполнить ввод / вывод. Вот где BIOS прерывания пригодятся.
  • У вас есть прямой контроль над памятью и устройствами, подключенными к системе, поэтому нет подкачки страниц, нет нарушений доступа, нет защиты памяти, нет параллелизма и так далее, и так далее. Эти функции облегчают игру в гольф по-настоящему креативными программами.

Я изменил ваш код, чтобы работать как плоский двоичный файл. Это очень просто:

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, "$"

Выходной двоичный файл имеет размер всего 32 байта. Я считаю, что можно уменьшить размер еще больше, но это только отправная точка.

Собрать с nasm -fbin file.asm -o file.com. Обратите внимание, что этот пример был сделан для NASM, но вы можете свободно перевести его в FASM, и он будет работать безупречно.

Кшиштоф Шевчик
источник
Я не могу поверить, что я ответил на этот вопрос и вернулся к нему от Google
Кшиштоф Шевчик