неinvoke'абельная либа

Тема в разделе "WASM.BEGINNERS", создана пользователем defaultplayer, 7 сен 2006.

  1. defaultplayer

    defaultplayer New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    214
    создаю def, вписываю EXPORTS MessageBoxA@16, скармливаю LIB.EXE, получаю либу, вызываю MessageBoxA один раз по call другой по invoke, один раз линкую с invoke'абельной либой из масма, другой раз с той которую создал. Компилю, - все прекрасно компилится в обоих случаях, только во втором прога стартует с экзепшеном. Закидываешь в иду, та показывает вход, секции, вроде все как полагается, запускаешь под ее отладчиком, - пишет экзепшн такой-то, закидываешь в олли, переходишь на точку входа, тоесть на адрес 00401000, так как он вообще ее не находит, пытаешся поставить бряк, прога пишит, что вы пытаетесь поставить бряк в не секции кода. подскажите плз че не линкуеться нормально с неinvoke'абельной либой?
     
  2. defaultplayer

    defaultplayer New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    214
    содержимое файла .def

    LIBRARY export
    EXPORTS MessageBoxA@16

    содержимое файла .asm

    Код (Text):
    1. .386
    2. .Model Flat,StdCall   ; 32 bit memory model
    3. Option Scoped         ; local labels are enabled, global labels inside
    4.                       ; PROC should be defined with double colons (LABEL::)
    5. Option CaseMap:None   ; case sensitive
    6.  
    7.  
    8.  
    9.  
    10. include windows.inc
    11. include user32.inc
    12.  
    13. ;includelib user32.lib ; это масмовская invoke'абельная библиотека, с ней компилится и прога работает
    14.  
    15. includelib  <export.lib> ; это неinvoke'абельная библиотека , та которая создалась из вышеописанного файла .def, с ней компилится но прога не стартует, точнее стартует но неправильно
    16.  
    17.  
    18. .data
    19.  
    20.  
    21. str1 db 'ggg',0
    22.  
    23.  
    24. .code
    25.  
    26. start:
    27.    
    28.    
    29. ;   push MB_OK
    30. ;   push offset str1  
    31. ;   push offset str1
    32. ;   push 0
    33. ;   call MessageBox
    34.  
    35.    invoke MessageBox,0,addr str1, addr str1,MB_OK
    36.    
    37.    ret
    38.  
    39. end start
    исходя из туториала ICZELIONа должно работать если MessageBox вызывается по call, так как MASM не будет проверять правильность параметров, но компилится в обоих случаях, а не работает.
     
  3. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    defaultplayer
    А чего ты добиваешься? У тебя в импорте ведь не user32!MessageBoxA будет.
     
  4. defaultplayer

    defaultplayer New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    214
    да, я начал копать и выкупил что, точно, только в импорте MessageBoxA будет, а никакой инфы о user32.dll нет, потом переписал в файле .def

    LIBRARY user32.dll
    EXPORTS MessageBoxA@16

    и все равно ничего не добился хотя в импорте появился user32!MessageBoxA, начал сравнивать бинарники нормальной проги и этой, нашел кое-какие расхождения, хотя не понял пока связаны ли они с неработспособностью проги
     
  5. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    defaultplayer
    Нет, что ты хочешь получить в конце? Научиться самому создавать lib? Это читал? Или ты хочешь создать lib от собственной dll?
     
  6. defaultplayer

    defaultplayer New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    214
    да читал, я выше писал "исходя из туториала ICZELIONа". Я пытаюсь по его туториалу создать "своими руками" неinvoke'абельную библиотеку, не из своей длл а из user32, но прога которую я собираю с этой библиотекой работает некорректно, поэтому и спрашиваю, что я не так делаю, мож сталкивался кто, мож в туториале что-то неверно или может просто недописано.
     
  7. defaultplayer

    defaultplayer New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    214
    оказывается ранее прога нехотела грузится, потому что в строке LIBRARY в файле .def писал всякую чушь, соответственно после сборки в импорте генерился бред, точнее какое то другое имя dll которую надо было подгружать, загрузчик соответственно ее не находил и о user32.dll тоже ниче не знал, поэтому прога и "прибивалась, так и не успевши загрузится". Подправил .def на LIBRARY user32, прога стартует, user32.dll подгружается, только загрузчик пишет мол "точка входа в процедуру MessageBoxA@16 не найдена в библиотеке user32.dll", как оказалось причина этому следующая: в туториале когда он объясняет как создать неinvoke'абельную библиотеку, в примере он приводит библиотеку из одной функции, а в user32.dll их много, а я пытался создать либу только с функцией MessageBoxA, короче для выхода из ситуации понадобилось вписать в строку EXPORTS еще и ее ординал MessageBoxA@16 @477, но еще интересно и остается вопрос открытым для меня, почему в туториале он в своей единственной функции, в файле .def не пишет общий объем входящих параметров в функцию, и даже если таковых и нет, то все равно должна быть запись вида GetSomeLine@0, потому что нормальной линковки не происходит. а, и еще он пишет что: "Вы получили .lib, которую можете использовать вместе с MASM, пока вам не требуется использовать 'invoke'", компилю, используя invoke, чудно тоже все работает, непонятно !!
     
  8. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    defaultplayer
    В def заносятся имена экспортируемых символов в том виде, в котором они прописываются в таблицах импорта/экспорта. @X в таблицы не попадает, т.к. загрузчику знать ничего не надо о соглашениях о вызове и кол-ве параметров - эта информация интересна только компилятору и, иногда, линкеру. Кстати, можно всё-таки экспортировать имена символов вместе с манглингом (@X и т.д.), но в этом просто нет необходимости.

    Для использования invoke достаточно предварительно указать PROTO, т.е. прототип внешней функции. Для call достаточно extern/externdef.
     
  9. defaultplayer

    defaultplayer New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    214
    еще больше вопросов возникло :), ладно, постараюсь дальше сам разобраться, если уже конкретно какой-то ком будет, то спрошу, за ответы спасибо!!
     
  10. defaultplayer

    defaultplayer New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    214
    Все, вопросов больше не имею, разобрался :)

    Quantum

    Кстати в одной из тем некий человек писал что внешнеиспользуемую функцию описывают так extern some_proc:near, а ты отписал что в масме можно хоть dword, просто если описывать как near, то создается все как положено, переменная в импорте, процедура с jumpом на ее содержимое и т.д., а вот если описывать dwordом, то просто создается глобальная переменная с хламом каким-то, и call будет на ее содержимое, короче прога не работоспособна, ты имел ввиду просто что компилятор прохавает такую запись или что?
     
  11. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    defaultplayer
    Если это импортируемая функция (типа USER32!MessageBoxA, KERNEL32!ExitProcess и т.д.), то dword вполне успешно заменяет near:
    EXTERN __imp__MessageBoxA@16:lol: WORD
    masm32 такое переваривает и всё прекрасно работает. call или jmp действительно ссылаются на ячейку в памяти (в IAT):
    call DWORD PTR [__imp__MessageBoxA@16]
     
  12. defaultplayer

    defaultplayer New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    214
    я все равно наверно не могу понять чего то важного, потому что непойму к чему тогда вся эта суета с создание асм файла с процедурами пустышками и т.д. ICZELION пишет: "Hапример, вы можете решить, что если вы измените имена функций в .def-файле, чтобы туда входило "@xx", библиотека импорта может заработать как надо. Поверьте мне. Это не будет работать.", ну почему не будет, если я включаю в строку EXPORTS @16 @477, скармливаю LIB.EXE, получаю либу. В коде вызываю MessageBoxA по invoke и все компилится и работает, а библиотека как он говорит неinvoke'абельная, тоесть я не создаю никаких асм файлов с процедурами и не компилю как длл проект, для того чтобы получить полноценную либу как он пишет.
     
  13. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    defaultplayer
    Очень просто. Эти @xx далее попадут в IAT приложения, которое собирается использовать данную DLL, но в экспорте DLL нет никаких @xx. Поэтому загрузчик будет ругаться.
     
  14. defaultplayer

    defaultplayer New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    214
    я пытаюсь сказать что прога работает :) почему? если исходя из его слов не должна, или тогда что он имел ввиду под словами "Поверьте мне. Это не будет работать."
     
  15. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    defaultplayer
    Вопрос из серии "что я делаю не так?" Если сделать так как написал автор, то работать не будет - сам когда-то проверял.
     
  16. defaultplayer

    defaultplayer New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    214
    Хорошо, идем по его туториалу, в точности так как он пишет:

    я создаю def файл, в строке EXPORTS вписываю MessageBoxA без @16, создаю из этого файла либу и все верно, как он и говорит, могу использовать данную либу, только если для вызова MessageBoxA буду использовать push, call, тоесть код получается следующего вида:

    Код (Text):
    1. .386
    2. .Model Flat,StdCall   ; 32 bit memory model
    3. Option Scoped         ; local labels are enabled, global labels inside
    4.                              ; PROC should be defined with double colons (LABEL::)
    5. Option CaseMap:None   ; case sensitive
    6.  
    7. include windows.inc
    8. includelib <user32.lib>  ; либа которую создали, без @16
    9.  
    10. extern MessageBoxA:near
    11.  
    12. .data
    13.  
    14. str1 db 'ggg',0
    15.  
    16. .code
    17.  
    18. start:
    19.    
    20.    push MB_OK
    21.    push offset str1  
    22.    push offset str1
    23.    push 0
    24.    call MessageBoxA
    25.    ret
    26.  
    27. end start
    вышеприведенный код работает чудесно, если вызвать MessageBoxA используя invoke работать не будет.

    Далее: он пишет, цитирую: "Hапример, вы можете решить, что если вы измените имена функций в .def-файле, чтобы туда входило "@xx", библиотека импорта может заработать как надо. Поверьте мне. Это не будет работать".

    Проделываем вышенаписанное: в файле def, в строку EXPORTS вписываю MessageBoxA@16 и как оказалось для "полной" работоспособности программы нужно обязательно вписать ординал @477 функции, которая импортируется, иначе при загрузке проги небудет найдена точка входа в функцию. Если операцию по вписыванию ординала в файл def считать расхождением с написанным в туториале, то его дальнейшие выводы о неработоспособности проги с использованием invoke верны, но к чему тогда дальнейшее написание туториала о том что надо создать асм файл с процедурами пустышками, компилить это все как длл проект для получения invoke'абельной либы, чтобы потом можно было использовать invoke, если достаточно вписать ординал и все, пользуйся хоть call, хоть invoke.

    содержимое файла .def:

    LIBRARY user32
    EXPORTS MessageBoxA@16 @477

    содержимое файла .asm

    Код (Text):
    1. .386
    2. .Model Flat,StdCall   ; 32 bit memory model
    3. Option Scoped         ; local labels are enabled, global labels inside
    4.                       ; PROC should be defined with double colons (LABEL::)
    5. Option CaseMap:None   ; case sensitive
    6.  
    7. include windows.inc
    8. includelib <user32.lib>  ; либа с вписанным ординалом
    9.  
    10. MessageBoxA PROTO :DWORD,:DWORD,:DWORD,:DWORD
    11. MessageBox equ <MessageBoxA>
    12.  
    13. .data
    14.  
    15. str1 db 'ggg',0
    16.  
    17. .code
    18.  
    19. start:
    20.    
    21.       invoke MessageBox,0,addr str1, addr str1,MB_OK
    22.  
    23.    ret
    24.  
    25. end start
    Вышеприведенный код работает чудесно, понадобилось только вписать в def ординал. Вообщем я не могу понять, чего я не догоняю во всем этом
     
  17. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    А в другой версии USER32.DLL ординал может оказаться совсем другим.
     
  18. defaultplayer

    defaultplayer New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    214
    ок, я понял. он просто не до конца раскрыл тему. Но и на том спасибо. Единственное, понять бы, что отличает полноценную invoke'абельную библиотеку от той что создал, тоесть что заставляет прогу работать без всяких ординалов, было бы неплохо.
     
  19. defaultplayer

    defaultplayer New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2006
    Сообщения:
    214
    можно еще вопрос в догонку? :)

    при явном вызове функции создается переменная в импорте и процедура с jumpом на ее содержимое, и при неявном вызове или использовании имени тоже самое. Вопрос: можно как-то отказаться от создания процедуры, только переменная в импорте, так как вызывать функцию не нужно, нужно только чтобы загрузчик положил туда ее адрес?
     
  20. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    defaultplayer
    Имена API функций в экспорте не содержат суффиксов @n. В данном случае импорт не вызывает ошибки только из-за того, что указан ординал. Кстати, мне кажется, что сам Iczelion не полностью исследовал проблему и можно заставить invoke работать с "неинвокабельной" либой, если правильно указать прототипы. Например, следующий код собирается с неинвокабельной либой, только малейшее изменение в коде приводит к ошибке из-за того, что адрес функции в импорте указан абсолютный, а в общем случае его нужно высчитывать по формуле... Если ещё немного поиздеваться над масмом, то, думаю, можно заставить такое работать и в общем случае. В идеале достаточно убрать PTR в EXTERNDEF, но тогда у компилятора начинает ехать крыша. Лишний раз убеждаюсь, что фасм лучше :)
    Код (Text):
    1. .386
    2. .model flat,stdcall
    3.  
    4. pr4 TYPEDEF PROTO :DWORD,:DWORD,:DWORD,:DWORD
    5. EXTERNDEF C MessageBoxA:PTR pr4
    6. MessageBox TEXTEQU <MessageBoxA[4056]>
    7. includelib user32.lib
    8.  
    9. .CODE
    10.  
    11. MsgBoxText db "Hello, world!",0
    12. MsgCaption db "test",0
    13.  
    14. start:
    15.     invoke MessageBox, 0, OFFSET MsgBoxText, OFFSET MsgCaption, 0
    16.     ret
    17.  
    18. END start
    Чтоб в импорте была функция, которая явно в коде не используется? Такое можно запросто сделать в фасме (см. пример "hello world" в пакете фасма). В масме такого сделать нельзя, т.к. в масме импорт генерирует линкер.