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

Скачивание файла из 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 в файл. Скачивает файл объект XmlHttpRequest из библиотеки 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)
	}
}
В коде используется объект XmlHttpRequest, для его создания необходимы 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
Размещено в Без категории
Показов 1349 Комментарии 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.cyberforum.ru/», это будет всего лишь 30 байт, смотрите как коротко.
    Запись от Замабувараев размещена 06.12.2021 в 19:23 Замабувараев вне форума
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2023, CyberForum.ru