Требуется написать что-то типа Код (Text): void Proc() { const char name[] = "value123"; ***** } При этом требуется чтобы сама инициализация переменной и ей данных находились среди кода функции. На асм'е всё решалось бы просто: Код (Text): jmp _next name: db "value", 0 _next: А вот как такое провернуть на Си? Ни static ни const не помогают, данные всё равно располагаются за пределами функции. Пока что нашел только один способ, типа Код (Text): сhar name[12]; *(DWORD*)name = 'ulav' *(DWORD*)(name + 4) = '321e' *(DWORD*)(name + 8) = 0 Но это очень не удобно. Может есть нормальный способы? P.S. способы должны быть совместимы с x64 P.P.S Компилятор - VS 2008
slesh Произвольные данные определяются в коде через __asm _emit в студии и через __asm (".byte ") в gcc.
GoldFinch Код (Text): char* buf; __asm { push eax call loc0 loc0: pop eax add eax, 9 mov buf, eax jmp loc1 __emit 0x30 __emit 0x31 __emit 0x32 __emit 0x33 __emit 0x00 loc1: pop eax } В buf получается строка '0123'
только посимвольное задание строки: Код (Text): const char name[] = {'v', 'a', 'l', 'u', 'e', '1', '2', '3'}; в результате код будет, что-то типа: Код (Text): mov [esp + <смещение_буфера_на_стеке>], <символ> ; и так для каждого символа
Rel только поправка: в коде функции самой строки не будет, а будет mov [esp + <смещение_буфера_на_стеке>], <символ> строка будет в стеке. Но если цель - базонезависимый код, то можно и так.
Опять же, всё что с использованием ASM не походит, т.к. VS не даёт использовать ASM под X64, а использовать сторонние obj файлы неудобно. const char name[] = {'v', 'a', 'l', 'u', 'e', '1', '2', '3'}; Этот способ для инициализации строки удобнее конечно выйдет, но по размеру больше чем *(DWORD*)name = 'ulav'
Rel gcc может в asm-вставку подсовывать пасхальные яйца. Недавно делал параллельный jpeg-декодер и решил ускорить процесс вот такой вставкой: Код (Text): static inline unsigned char descale_and_clamp(int x, int shift) { __asm volatile (".intel_syntax noprefix\n\t" "mov ecx,%[shift]\n\t" "mov eax,1\n\t" "shl eax,cl\n\t" "shr eax,1\n\t" "add eax,%[x]\n\t" "sar eax,cl\n\t" "add eax,0x80\n\t" "cmp eax,0x80000000\n\t" "sbb edx,edx\n\t" "add eax,0xFFFFFF00\n\t" "sbb ecx,ecx\n\t" "or eax,ecx\n\t" "and eax,edx\n\t" ".att_syntax prefix\n\t" : : [x]"r"(x), [shift]"r"(shift)); } Под cygwin gcc всё отлично работало, а под unix на выходе декодера сплошной серый фон вместо изображения. С учётом того, что даже posix-совместимый код я всегда пишу только под виндой, а под unix у меня опыта отладки (да и инструментария) почти нету, пришлось изрядно помучаться, чтобы разобраться, в чём проблема. Оказалось, что под unix вставка компилировалась в такую: Код (Text): push ebp mov ebp, esp mov eax, [ebp+08h] mov edx, [ebp+0Сh] mov ecx, edx mov eax, 1 shl eax, cl shr eax, 1 add eax, eax sar eax, cl add eax, 80h cmp eax, 80000000h sbb edx, edx add eax, 0FFFFFF00h sbb ecx, ecx or eax, ecx and eax, edx pop ebp retn P.S. Блин. Только сейчас подумал, что надо было clobbered registers list указать. Но в любом случае, если я пишу add eax,%[x], я ожидаю, что будет add eax,[ebp+8], а не промежуточные регистры.
незнаю компилер же не дурак, без инлайна не вижу выхода: Код (Text): void CALLME() { char *bufaddr; __asm { mov dword ptr [bufaddr], offset preallocated jmp outblock preallocated: call $ ; 20 bytes (4 far calls) call $ call $ call $ outblock: } // write to the call's place lstrcpyn(bufaddr, "ALALALA", 20); // ... } VirtualProtect(CALLME, 1, PAGE_EXECUTE_READWRITE, &pr); CALLME(); samuraishowdown ой, не обратил внимание на твой кодес, но тож самое почти в голову пришло а для х64 в студии это все равно бесполезно тк там инлайн асм запрещен. проще функцию переписать на асме полностью и вытащить отдельно, чтоб например фасмом компилилась в COFF на пребилд эвенте c учетом #ifdef _WIN64 ... да и делов
sn0w и чо это за бред? Код (Text): void CALLME() { char bufaddr[20]; lstrcpyn(bufaddr, "ALALALA", 20); // ... } тож самое ток без извратов%
в твоем случае данные будут в стеке а не в теле функции. впрочем я еще один способ придумал тока без асма, покамест дебажу
sn0w % lstrcpyn(bufaddr, "ALALALA", 20); "ALALALA" - константа, по твоему куда её студия вкомпалит то??
slesh к стате по поводу ДВОРД-ов, я почти так и делаю обычно DWORD val[] = {'ulav','321e','\0'} тож не особо, но поудобней чем *(val+8)
ASMatic очевидно что компилер воткнет строку в секцию rdata или data, тогда как тело нашей функции находится в секции text, и нам надо прямо написать в код самой функции. без асма у меня вышло вот такое. можно еще eip/rip ретривнуть через CONTEXT::Eip впринципе, но решил так. пс клей не нюхал. Код (Text): #include <windows.h> #pragma comment(linker, "/ENTRY:start") LPSTR g_data_stuff; void CALLME() { *(DWORD*)0=0; goto exec_code; GetTickCount(); // <--- g_data_stuff points there after exception GetTickCount(); // (this is like a room for our string in function body) GetTickCount(); // GetTickCount(); // exec_code: char rpt[128]; lstrcpyA(g_data_stuff, "ololiolol"); wsprintf(rpt, "Address of CALLME: %08X\nAddress of buffer: %08X\nBuffer Text: %s", CALLME, g_data_stuff, g_data_stuff); MessageBox(0, rpt,0,0); } LONG WINAPI VectoredHandler(_EXCEPTION_POINTERS *ExceptionInfo) { // for x86 g_data_stuff = (LPSTR)ExceptionInfo->ContextRecord->Eip; ExceptionInfo->ContextRecord->Eip += 10; // в зависимости от длины *0 = 0 // // без оптимизаций у меня такой вот код генерит, поэтому +14 от экзепшна до call GetTickCount // //12: *(DWORD*)0=0; //00401003 C7 05 00 00 00 00 00 00 00 00 mov dword ptr ds:[0],0 //13: goto exec_code; //0040100D EB 1A jmp exec_code (401029h) //0040100F EB 18 jmp exec_code (401029h) g_data_stuff += 14; // *0=0 + 2jmp aka goto return EXCEPTION_CONTINUE_EXECUTION; } int WINAPI start() { DWORD prot; VirtualProtect(CALLME, 1, PAGE_EXECUTE_READWRITE, &prot); AddVectoredExceptionHandler(1, VectoredHandler); CALLME(); ExitProcess(0); }
Если нужно, чтобы строка оказалась просто в секции .text, можно так: Код (Text): #pragma const_seg(".text") void func() { const char str[]="test str"; } Правда внутри кода func строка при этом не окажется...