Застрял вот на проблеме с правильным обьявлением entry-point. 1.c: Код (Text): <font color="green] int main() { return 1; } </font><!--color--> build.bat: Код (Text): <font color="green] @echo off set align=-Wl,--file-alignment,0x20 -Wl,--section-alignment,0x20 set linko=-Wl,-e,main set libs=-L../lib/ ..\lib\crt2.o -luser32 -lkernel32 -lmingw32 -lmsvcrt -lgcc gcc 1.c -O3 -s -ffast-math -mwindows -nostdlib %align% %linko% %libs% </font><!--color--> Жалуется так: ld.exe: warning: cannot find entry symbol main; defaulting to 00400020 Чего ему не хватает собственно?
IceStudent Нет не помогает, я и такой прототип задавал, и вот такой: <font color="green]int APIENTRY WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)</font><!--color--> Сдается мне что линкер по какой-то причине просто не видит обьявленной функции, т.к. если бы не совпадали прототипы ошибка была бы наверное другая. С mvsc таких проблем нет - что ни задай - все кушает. По идее правильный прототип с void аргументом, я потрассировал несколько прог на VC++, они начинались с WinMainStartup (см. Vc7\crt\src\crt0.c): Код (Text): #ifdef _WINMAIN_ #ifdef WPRFLAG int wWinMainCRTStartup( #else /* WPRFLAG */ int WinMainCRTStartup( #endif /* WPRFLAG */ #else /* _WINMAIN_ */ #ifdef WPRFLAG int wmainCRTStartup( #else /* WPRFLAG */ int mainCRTStartup( #endif /* WPRFLAG */ #endif /* _WINMAIN_ */ void ) Если задать aligment в 0x400 программа начинает работать несмотря на воринг, но при этом раздувается до 4Кб (так она всего 960 байт).
Однако нет. Всем спасибо, промучавшись 2 часа, я нашел проблему - компилятор мало того что искажает имя функций, он к ним еще и символ подчеркивания добавляет. Поэтому обьявление должно быть таким: extern "C" int main() А параметры линкера: -e _main З.Ы. Достаточно было заглянуть в обьектник промежуточный. Вместе с тем обидно - назначение entry работспособности проге не добавило - при загрузке выводится "1.exe не является приложением Win32".
Теперь вылепился вопрос - как заставить линкер соединить все секции в одну (.text + .data + .idata + .rdata), или ld здесь мне не помощник (т.е. надо юзать unilink) или как заставить его генерить рабочий exe-файл размером < 2Kb.
Попробуй глянуть в диру \mingw32\lib\ldscripts\ там какие-то интересные файлы. правда, ничего не понятно мне в них
а файлик точно называется 1.c, не 1.cc и не 1.cpp? в *nix gcc (точнее C-frontend) никаких искажений имён, не выполняет. Этим g++ балуется. И то упомянутый extern "C", говорит о том же: программа компилируется как C++ программа, не как C. Насколько я помню свой недолгий опыт пользования gcc с target=i386-cygwin-pe, надо передать также опцию --subsystem= А, насчёт, собрать все секции в одну... Здесь я согласен со S_T_A_S_ наверное надо искать в ldscripts, и скорее всего писать новый скрипт сборки.
И ещё, мне кажется что entry point должен быть не main, а дефолтовый -- _start, который должен быть определён в crt*.o. А main будет из него вызыватся.
rgo Пробывал в обоих вариантах, от .c пришлось отказаться в пользу .c++ - с ним не требуется подлючаться RTL (т.е. crt2.o и еще несколько зависимых либ), и использовать только -lkernel32 & -luser32. Со знаком подчеркивания ситуация одинаковая в обоих случаях - но в случае не задания extern "C" имя main искажается еще сильнее. В данной программе использовать стандартный entry никчему - инициализация RTL не нужна, используются только WinAPI функции. Со скриптами еще не разбирался.
Вобщем я обламываюсь пока достичь лучшего - сделал тоже самое на ассемблере: Код (Text): .intel_syntax ; Source file "1.s" .text caption: .ascii "helloworld\0" textmsg: .ascii "Hi! I'm the example program!\0" .global main /* .type main, @function */ main: push ebp mov ebp, esp xor eax, eax push eax push offset caption push offset textmsg push eax call _MessageBoxA@16 leave ret Компилирую его с ключами: <font color="green] @echo off rem build.bat set addp= -Wl,-e,main,-b,pei-i386 gcc 1.s -o 1.exe -Os -s -masm=intel -mwindows -nostdlib -luser32 %addp% </font><!--color--> В итоге получается EXE файл размером в 2048 байт. Если использовать скрипт линкера отменяющий выравнивание (параметр -n), файл уменьшается до 1720 байт, но становится не работоспособным. Файл с той же функциональностью на С++ весит 2560 байт, но в основном из-за того что строки компилятор помещает в отдельно для этого созданную секцию ресурсов. Как его отучить от этого я пока инфы не нашел.
На самом деле, есть такой пакет binutils -- который пользуя libBFD, может делать с объектным кодом кучу всяких вещей, от вывода данных о файле, типа списка символов, до дизассемблирования секций, вырезания отладочной информации/символов или даже секций, и перевода из одного формата в другой. Ручаться, что с его помощью можно слить две секции в одну, не буду, но мне кажется что можно. Но пакет, выполнен в лучших традициях *nix (Software Toolbox), и как им пользоваться без sh (ну или csh и пр), я не представляю. Хотя я точно также не представляю как вообще можно работать с компутером без sh
rgo libBFD - как я понял библиотека, которую нужно компилировать с проектом. Мне несовсем ясно как в этом деле может помочь либа. Конкретно из пакета binutils у меня есть утилиты, но с ними я еще не разбирался. Что касается sh - это не проблема, т.к. у меня есть MSYS - довольно полноценная оболочка с поддержкой скриптов. Недавно пытался с ее помощью собрать gcc 4.0.1, но потерпел неудачу на этапе конфигурирования - перед самым созданием makefile вывелась ошибка: "creating ./config.status creating Makefile sed: file conftest.s1 line 85: Unterminated `s' command" Сам я привык к cmd, который конечно смотрится примитивным на фоне никсовых команд-интерпретаторов, но его на основные задачи хватает. [edit] Хм. Странности какие-то, я сегодня попробывал опять сконфигурить - и прошло. Сейчас во всю идет сборка, и неизвестно когда она закончится. До конца сборки так и не дошло, хотя основные бинарники не собрались. Попробывал еще раз - уже конфигурация перестала работать нормально.
alpet Я когда-то ковырял эту тему (минимальное приложение на gcc). Копал в сторону редактирования скриптов линкера (которые подключаются опцией ld -T xxx). Удалось многие секции засунуть в одну и сократить размер. А вообще у gcc жутко "мусорный" компилятор. Ну например выравнивание константных строк, процедур и прыжков у него прописано насмерть внутри самого gcc (я правил это бинарным патчем - размеры получаемых exe'шников уменьшились)... Ну и еще куча таких же "приколов" от разработчиков; может в 4.х что-то пофиксили, не знаю еще. Еще способ - заставить gcc сгенерить .s файл и пройтись там руками, хлама всякого там хватает. В аттаче пример i386pe.x у которого некоторые секции сведены воедино. _2103307015__i386pe.x
Нет, libBFD это либа, через которую в *nix происходит, вся user-mode работа с объектными файлами (были б в *nix актуальны вирусы, думается мне, и они бы тоже инфицировали используя libBFD). И binutils её активно пользует, по сути предоставляя все возможности libBFD для командной строки.