Obj файлы на топчане или...


Битва за API - часть 2


Хорошая новость — линкер заглатывает наживку и пытается переварить файл. Плохая новость — это у него не получается. А не получается потому, что он не распознает имена API функций, которых в нашем демонстрационном примере аж целых 40 штук! В переводе с английского ругательство "error LNK2001: unresolved external symbol _WriteFile" звучит как "Егор: LNK2001: неразрешимый внешний символ _WriteFile".

Сразу же возникает вопрос: откуда взялся знак прочерка и почему это WriteFile вдруг стала неразрешимым символом?! Смотрим в ассемблерный листинг. Контекстный поиск по "_WriteFile" ничего не дает! API-функция там объявлена _без_ знака прочерка:

 

; Segment type:      Externs

; BOOL __stdcall WriteFile(HANDLE hFile, LPCVOID lpBuffer,

; DWORD nBytesToWrite, LPDWORD lpNumberOfBytesWritten,LPOVERLAPPED lpOverlapped);

       extrn WriteFile:dword

Листинг 4 объявления API-функций в ассемблерном листинге

А теперь открываем demo_3.obj в любом hex-редакторе (например, в FAR'е по <F3> или в HIEW'е) и повторяем процедуру поиска еще раз:

 

Рисунок 1 просмотр obj-файла в hex-редакторе

Строка "WriteFile" встречается дважды (см. рис. 1) — один раз со знаком прочерка, другой — без. Вот этот самый прочерк линкеру и не нравится. Откуда же он берется?! А оттуда! Курим листинг 4 и убеждаемся, насколько IDA Pro коварна и хитра. Тип API-функции (stdcall) задан только в комментарии! Транслятор же комментариев не читает, и берет тип по умолчанию, которым в данном случае является Си (cdecl), предписывающий перед всеми символьными именами ставить знак прочерка, что, собственно говоря, и происходит.

Кстати говоря, комментарий неправильный. Потому что тип вызова никак не stdcall, согласно которому, транслятор должен превратить "WriteFile" в "_WriteFile@20", где 20 — размер аргументов в байтах, заданный в десятеричной нотации. Это вообще не сама функция, а двойное слово, в которое операционная система заносит эффективный адрес WriteFile при загрузке PE-файла в память. В библиотеке KERNEL32.LIB (входящей, в частности, в состав SDK) ему соответствует имя "__imp__WriteFile@20". Именно такое "титул" должен носить прототип API-функции, если мы хотим успешно слинковать obj-файл и именно это имя мы используем при вызове API-функции при программировании на "голом" ассемблере (без включаемых файлов). Вот только IDA Pro во все эти подробности не вникает, перекладывая  их на наши плечи и хвост.




Начало  Назад  Вперед