Всем привет, вот хочу запрячь встроенный ассемблер в VS, да напоролся на недоразумение эдакое. Следующий код: Код (Text): #include <windows.h> char msgboxC[] = "Hello, world from C code"; char msgboxAsm[] = "Hello, world form Asm code"; void main() { MessageBox(0,&msgboxC[0],0,0); _asm { push 0 push 0 push offset msgboxAsm push 0 call MessageBox } } При запуске первый MessageBox работает, а второй - нет! После call MessageBox вылетает exception at 0x00402000 in msgbox_in_asm.exe: 0xC0000005: Access violation reading location 0xffffffff. IDA после дизассемблирования выдает следующее: Код (Text): .text:00401000 main proc near .text:00401000 push 0 .text:00401002 push 0 .text:00401004 push offset msgboxC ; "Hello, world from C code" .text:00401009 push 0 .text:0040100B call ds:__imp__MessageBoxA@16 ; __declspec(dllimport) MessageBoxA(x,x,x,x) ;опкод этой инструкции - FF 15 00 20 40 00 .text:00401011 push 0 .text:00401013 push 0 .text:00401015 push offset msgboxAsm ; "Hello, world form Asm code" .text:0040101A push 0 .text:0040101C call near ptr __imp__MessageBoxA@16 ; __declspec(dllimport) MessageBoxA(x,x,x,x) ;опкод этой инструкции - E8 DF 0F 00 00 .text:00401021 retn .text:00401021 main endp Объясните кто-нибудь, почему генерируется разный код? Буду рад любой информации по использованию встроенного ассемблера в VS. Хелп читал, но там написано именно так делать. И еще, я отключил CRT (/entry:main), Buffer Security Check и включил выравнивание на 512 байт (/opt:nowin98), это позволило получить размер исполняемого файла в 2.5 кБ. Может быть в этом проблема? Всем спасибо. ЗЫ. Если я пишу в коде что-то типа call ds:MessageBox, то функция вызывается и опкоды одинаковые, только в коде появляется лишний байт%-|. Вот дизассемблированный код: Код (Text): .text:00401000 main proc near .text:00401000 push 0 .text:00401002 push 0 .text:00401004 push offset msgboxC ; "Hello, world from C code" .text:00401009 push 0 .text:0040100B call ds:__imp__MessageBoxA@16 ; __declspec(dllimport) MessageBoxA(x,x,x,x) .text:00401011 push 0 .text:00401013 push 0 .text:00401015 push offset msgboxAsm ; "Hello, world form Asm code" .text:0040101A push 0 .text:0040101C db 3Eh .text:0040101C call __imp__MessageBoxA@16 ; __declspec(dllimport) MessageBoxA(x,x,x,x) .text:00401023 retn .text:00401023 main endp
Хексдамп бы не помешал, но осмелюсь предположить. Незнаю как в 2003, но еще в 6-ой VS имелась фича с вызовом внешних функций - если просто писать call то глупый ассемблер так и делал call на адрес в IAT - т.е. просто прыгал на dword в iat и естесно все падало. Приходилось писать что-то вроде call ds:[MessageBoxA] Все дело в том что это не дельфя а нету тут jump таблиц, все надо вызывать как call dword ptr [xxxx]
Вот хексдамп первого варианта (в котором call MessageBox) из OllyDbg: Код (Text): 00401000 >/$ 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL 00401002 |. 6A 00 PUSH 0 ; |Title = NULL 00401004 |. 68 00304000 PUSH OFFSET msgbox_i.msgboxC ; |Text = "Hello, world from C code" 00401009 |. 6A 00 PUSH 0 ; |hOwner = NULL 0040100B |. FF15 00204000 CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA 00401011 |. 6A 00 PUSH 0 00401013 |. 6A 00 PUSH 0 00401015 |. 68 1C304000 PUSH OFFSET msgbox_i.msgboxAsm ; ASCII "Hello, world from Asm code" 0040101A |. 6A 00 PUSH 0 0040101C |. E8 DF0F0000 CALL <&USER32.MessageBoxA> 00401021 \. C3 RETN И второго (call ds:[MessageBoxA]: Код (Text): 00401000 >/$ 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL 00401002 |. 6A 00 PUSH 0 ; |Title = NULL 00401004 |. 68 00304000 PUSH OFFSET msgbox_i.msgboxC ; |Text = "Hello, world from C code" 00401009 |. 6A 00 PUSH 0 ; |hOwner = NULL 0040100B |. FF15 00204000 CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA 00401011 |. 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL 00401013 |. 6A 00 PUSH 0 ; |Title = NULL 00401015 |. 68 1C304000 PUSH OFFSET msgbox_i.msgboxAsm ; |Text = "Hello, world from Asm code" 0040101A |. 6A 00 PUSH 0 ; |hOwner = NULL 0040101C |. 3E:FF15 00204000 CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA 00401023 \. C3 RETN Можно ли это исправить? Вот нашел пример в хелпе, там идет обычный call: Код (Text): An __asm block can call C functions, including C library routines. The following example calls the printf library routine: // InlineAssembler_Calling_C_Functions_in_Inline_Assembly.cpp #include <stdio.h> char format[] = "%s %s\n"; char hello[] = "Hello"; char world[] = "world"; int main( void ) { __asm { mov eax, offset world push eax mov eax, offset hello push eax mov eax, offset format push eax [b]call printf[/b] //clean up the stack so that main can exit cleanly //use the unused register ebx to do the cleanup pop ebx pop ebx pop ebx } }
Ок, вариант call dword ptr [xxxx] работает, даже можно имя функции без скобок писать. Спасибо, Dr.Golova!