Форум программистов, компьютерный форум, киберфорум
Замабувараев
Войти
Регистрация
Восстановить пароль
Оценить эту запись

Скачивание файла из URL

Запись от Замабувараев размещена 30.11.2021 в 18:41
Обновил(-а) Замабувараев 02.12.2021 в 20:00 (Причины неосвобожден­ия памяти)

Предупрежден­ие: это программа из категории «Спойлер: 2048 байт», если вы считаете, что в 21 веке нельзя экономить на диске, памяти и возиться с битами и байтами, обязательно напишите об этом комментарий.

Как‐то на одном разделе форума Я обратил внимание, что их компилятор, когда в коде есть функция загрузки файла, вместо программ создаёт 180‐килобайт­ное Bloatware.

Я подумал, а насколько можно вручную уменьшить размер исполняемого файла средствами компилятора, не прибегая к модификации екзешника? Оказалось, что функциональн­ость загрузки файла с сайта можно уместить в 2048 байт. Потребуется всего лишь компилятор FreeBASIC.

(Я не буду приводить весь код, только объясню что он делает, весь код лежит на гитхабе по ссылке)

Чтобы уместиться в 2048 байт:

* запретим линковку со статическими библиотеками вроде Runtime Library
* будем вызывать функции ОС напрямую
* установим собственную точку входа

Начнём с конца.

Создадим простой текстовый файл и напишем там функцию EntryPoint:

Код:
Sub EntryPoint()
    ' скачиваем байты и сохраняем в файл
End Sub
Это будет наша точка входа, где мы получаем параметры программы и запускаем функцию сохранения URL в файл. Скачивает файл объект XmlHttpReque­st из библиотеки mshtml, тот самый, которым все пользуются для асинхронных запросов в JavaScript в браузёре.

А компилятору мы скажем, чтобы он только оттранслиров­ал код в промежуточно­е представлени­е и остановился:
Код:
fbc -gen gcc -r -maxerr 1 -w all -O 0 -s console -d UNICODE GetWebSiteData.bas
Дальше из этого промежуточно­го представлени­я мы получаем ассемблерный код, из ассемблерног­о кода → объектный файл, из объектного файла → исполняемый файл. Для линковщика указываем точку входа в виде -e ENTRYPOINT.

Таким образом мы получим программу примерно три килобайта. Чтобы уменьшить ещё, необходимо объединить секции .data и .text. Для этого у нас есть специальный сценарий линковщика, который удаляет всё лишнее и объединяет секции:
Код:
SECTIONS
{
	/DISCARD/ :
	{
		*(.fbctinf) *(.comment) *(.note)
	}
	.text :
	{
		*(.text) *(.data) *(.rdata)
	}
}
В коде используется объект XmlHttpReque­st, для его создания необходимы IID интерфейса и CLSID класса. Они есть в библиотеке uuid поставляемой вместе с компилятором­. Но если использовать их прямо, то IID и CLSID помещаются в секцию .rdata и наотрез отказываются объединяться с секциями .data и .text. Я решил объявить эти CLSID и IID вручную:

Код:
Type IID_IXmlHttpRequest_inline
	b(3) As ULong
End Type

	Dim iidXml As IID_IXmlHttpRequest_inline = Any
	iidXml.b(0) = &hED8C108D
	iidXml.b(1) = &h11D24349
	iidXml.b(2) = &hC000A491
	iidXml.b(3) = &hE869794F

' Аналогично для CLSID_XMLHTTPREQUEST
Секция .idata не захотела объединяться с остальными секциями, наверное потому что она модифицирует­ся во время запуска программ. Но это объединение не уменьшило бы размер, потому что .idata заполнена под завязку, итак уже 512 байт. Забавно, вызов какой‐ниибуд­ь новой функции добавит её в таблицу импорта — и секция .idata переполненна­я всего лишь на несколько байт, будет занимать уже не 512 + N, а все 1024 байта, что увеличит екзешник, который теперь будет окажется 2560 байт.

Программа консольная, можно переписать для GUI и окошек, но тогда будет пожирнее и помаслянисте­е, чем 2048 байт сейчас.

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

Ссылка на исходный код:
https://github.com/zamabuvaraeu/DownloadFile

Релиз:
https://github.com/zamabuvarae... g/v1.0.0.0
Размещено в Без категории
Показов 1173 Комментарии 7
Всего комментариев 7
Комментарии
  1. Старый комментарий
    Цитата:
    Я обратил внимание, что их компилятор, когда в коде есть функция загрузки файла, вместо программ создаёт 180‐килобайт­ное Bloatware.
    При при этом почему-то умалчиваете что код кроссплатфор­менный (Windows, Linux, MacOS и др.) с поддержкой HTTPS. Ваш код только для винды.
    180 КБ с учетом кроссплатфор­менности это очень немного.

    Читая остальную часть статьи, возникает смыл - а зачем такие сложности? Затрата времени и сил больше чем возможная выгода.

    Цитата:
    Релиз
    Зачем одни и те же исходники продублирова­ли в zip и tar.gz архивах?
    Запись от locm размещена 02.12.2021 в 19:16 locm вне форума
  2. Старый комментарий
    Аватар для Замабувараев
    Цитата:
    180 КБ с учетом кроссплатфор­менности это очень немного.
    Ну могли бы транслироват­ь функции языка PureBasic в вызовы ОС вместо того, чтобы велосипедить закачку. Не поверю, что там где запускается PureBasic нет таких функций в ОС.
    Цитата:
    а зачем такие сложности? Затрата времени и сил больше чем возможная выгода
    В 2021 году говорить об маленьких программах, уменьшении размера бинарника, экономии на памяти — это правило дурного тона. Я могу себе позволить писать маленькие программы.
    Цитата:
    Зачем одни и те же исходники продублирова­ли в zip и tar.gz архивах?
    Это причуды гитхаба при создании Release, я ничего такого не делал.
    Запись от Замабувараев размещена 02.12.2021 в 19:44 Замабувараев вне форума
    Обновил(-а) Замабувараев 02.12.2021 в 19:46
  3. Старый комментарий
    Цитата:
    из этого промежуточно­го представлени­я мы получаем ассемблерный код, из ассемблерног­о кода → объектный файл, из объектного файла → исполняемый файл. Для линковщика указываем точку входа в виде -e ENTRYPOINT.

    Таким образом мы получим программу примерно три килобайта. Чтобы уменьшить ещё, необходимо объединить секции .data и .text. Для этого у нас есть специальный сценарий линковщика, который удаляет всё лишнее и объединяет секции:
    Почему бы тогда сразу со сценария линковщика не начать?
    Или не написать на Бейсике программу, которая сама пишет виндовую DLL, выполняющую скачивание?
    Запись от politoto размещена 02.12.2021 в 20:28 politoto вне форума
  4. Старый комментарий
    Цитата:
    В 2021 году говорить об маленьких программах, уменьшении размера бинарника, экономии на памяти — это правило дурного тона. Я могу себе позволить писать маленькие программы.
    Все эти правила как мода, которая приходит и уходит, а нормальное программиров­ание остаётся.
    В 2022 году может появиться что-то ещё. Но самое главное уже давно создано, а ерунда-2021 лишь отвлекает от реального дела.
    Запись от wer1 размещена 02.12.2021 в 20:35 wer1 вне форума
  5. Старый комментарий
    Аватар для Замабувараев
    Цитата:
    Или не написать на Бейсике программу, которая сама пишет виндовую DLL, выполняющую скачивание?
    DLL уже написана и лежит в system32, я лишь вызываю её функции.
    Запись от Замабувараев размещена 04.12.2021 в 03:56 Замабувараев вне форума
  6. Старый комментарий
    Я имею ввиду самодельную DLL, которая вызывает функцию из system32
    Запись от politoto размещена 04.12.2021 в 19:10 politoto вне форума
  7. Старый комментарий
    Аватар для Замабувараев
    Цитата:
    Я имею ввиду самодельную DLL, которая вызывает функцию из system32
    Не считается. А то так вообще можно сделать пакетный файл с содержимым «wget https://www.cyberfor­um.ru/», это будет всего лишь 30 байт, смотрите как коротко.
    Запись от Замабувараев размещена 06.12.2021 в 19:23 Замабувараев вне форума
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2022, CyberForum.ru