сохранение строки в коде функции

Тема в разделе "LANGS.C", создана пользователем slesh, 23 дек 2011.

  1. slesh

    slesh New Member

    Публикаций:
    0
    Регистрация:
    6 фев 2009
    Сообщения:
    214
    Требуется написать что-то типа

    Код (Text):
    1. void Proc()
    2. {
    3.     const char name[] = "value123";
    4.     *****
    5. }
    При этом требуется чтобы сама инициализация переменной и ей данных находились среди кода функции.
    На асм'е всё решалось бы просто:
    Код (Text):
    1. jmp _next
    2. name:
    3.   db "value", 0
    4. _next:
    А вот как такое провернуть на Си?
    Ни static ни const не помогают, данные всё равно располагаются за пределами функции.
    Пока что нашел только один способ, типа
    Код (Text):
    1.     сhar name[12];
    2.  
    3.     *(DWORD*)name = 'ulav'
    4.     *(DWORD*)(name + 4) = '321e'
    5.     *(DWORD*)(name + 8) = 0
    Но это очень не удобно. Может есть нормальный способы?
    P.S. способы должны быть совместимы с x64
    P.P.S Компилятор - VS 2008
     
  2. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    А чем собсно 'char name[] = "value123";' не устраивает?
     
  3. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    это невозможно.
    пишите эту функцию на асме и линкуйте с кодом на Си
     
  4. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    slesh
    Произвольные данные определяются в коде через __asm _emit в студии и через __asm (".byte ") в gcc.
     
  5. kejcerfcrv

    kejcerfcrv New Member

    Публикаций:
    0
    Регистрация:
    16 дек 2011
    Сообщения:
    320
    Как же такой мощный компилятор не позволяет контролировать даже расположение строк ?
     
  6. samuraishowdown

    samuraishowdown New Member

    Публикаций:
    0
    Регистрация:
    6 мар 2011
    Сообщения:
    70
    GoldFinch
    Код (Text):
    1.     char* buf;
    2.     __asm
    3.     {
    4.         push   eax
    5.         call   loc0
    6. loc0:
    7.         pop    eax
    8.         add    eax, 9
    9.         mov    buf, eax
    10.         jmp    loc1
    11.         __emit 0x30
    12.         __emit 0x31
    13.         __emit 0x32
    14.         __emit 0x33
    15.         __emit 0x00
    16. loc1:
    17.         pop    eax
    18.     }
    В buf получается строка '0123'
     
  7. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.323
    только посимвольное задание строки:
    Код (Text):
    1. const char name[] = {'v', 'a', 'l', 'u', 'e', '1', '2', '3'};
    в результате код будет, что-то типа:
    Код (Text):
    1. mov [esp + <смещение_буфера_на_стеке>], <символ> ; и так для каждого символа
     
  8. samuraishowdown

    samuraishowdown New Member

    Публикаций:
    0
    Регистрация:
    6 мар 2011
    Сообщения:
    70
    Rel

    только поправка: в коде функции самой строки не будет, а будет

    mov [esp + <смещение_буфера_на_стеке>], <символ>

    строка будет в стеке.

    Но если цель - базонезависимый код, то можно и так.
     
  9. slesh

    slesh New Member

    Публикаций:
    0
    Регистрация:
    6 фев 2009
    Сообщения:
    214
    Опять же, всё что с использованием ASM не походит, т.к. VS не даёт использовать ASM под X64, а использовать сторонние obj файлы неудобно.

    const char name[] = {'v', 'a', 'l', 'u', 'e', '1', '2', '3'};
    Этот способ для инициализации строки удобнее конечно выйдет, но по размеру больше чем
    *(DWORD*)name = 'ulav'
     
  10. ASMatic

    ASMatic New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2010
    Сообщения:
    233
    можно к прожу файлик *.asm подключить + еще парочка настроек и будет все норм компилится под х64
     
  11. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.323
    переходи на компилятор gcc семейства...
     
  12. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    Rel
    gcc может в asm-вставку подсовывать пасхальные яйца. Недавно делал параллельный jpeg-декодер и решил ускорить процесс вот такой вставкой:
    Код (Text):
    1. static inline unsigned char descale_and_clamp(int x, int shift)
    2. {
    3.     __asm volatile (".intel_syntax noprefix\n\t"
    4.                     "mov ecx,%[shift]\n\t"
    5.                     "mov eax,1\n\t"
    6.                     "shl eax,cl\n\t"
    7.                     "shr eax,1\n\t"
    8.                     "add eax,%[x]\n\t"
    9.                     "sar eax,cl\n\t"
    10.                     "add eax,0x80\n\t"
    11.                     "cmp eax,0x80000000\n\t"
    12.                     "sbb edx,edx\n\t"
    13.                     "add eax,0xFFFFFF00\n\t"
    14.                     "sbb ecx,ecx\n\t"
    15.                     "or eax,ecx\n\t"
    16.                     "and eax,edx\n\t"
    17.                     ".att_syntax prefix\n\t" : : [x]"r"(x), [shift]"r"(shift));
    18. }
    Под cygwin gcc всё отлично работало, а под unix на выходе декодера сплошной серый фон вместо изображения. С учётом того, что даже posix-совместимый код я всегда пишу только под виндой, а под unix у меня опыта отладки (да и инструментария) почти нету, пришлось изрядно помучаться, чтобы разобраться, в чём проблема. Оказалось, что под unix вставка компилировалась в такую:
    Код (Text):
    1. push    ebp
    2. mov     ebp, esp
    3. mov     eax, [ebp+08h]
    4. mov     edx, [ebp+0Сh]
    5. mov     ecx, edx
    6. mov     eax, 1
    7. shl     eax, cl
    8. shr     eax, 1
    9. add     eax, eax
    10. sar     eax, cl
    11. add     eax, 80h
    12. cmp     eax, 80000000h
    13. sbb     edx, edx
    14. add     eax, 0FFFFFF00h
    15. sbb     ecx, ecx
    16. or      eax, ecx
    17. and     eax, edx
    18. pop     ebp
    19. retn
    P.S. Блин. Только сейчас подумал, что надо было clobbered registers list указать. Но в любом случае, если я пишу add eax,%[x], я ожидаю, что будет add eax,[ebp+8], а не промежуточные регистры.
     
  13. sn0w

    sn0w Active Member

    Публикаций:
    0
    Регистрация:
    27 фев 2010
    Сообщения:
    958
    незнаю компилер же не дурак, без инлайна не вижу выхода:

    Код (Text):
    1. void CALLME()
    2. {
    3.     char *bufaddr;
    4.    
    5.     __asm
    6.     {
    7.         mov dword ptr [bufaddr], offset preallocated
    8.         jmp outblock
    9. preallocated:  
    10.         call $  ; 20 bytes (4 far calls)
    11.         call $
    12.         call $
    13.         call $
    14. outblock:
    15.     }
    16.  
    17.     // write to the call's place
    18.     lstrcpyn(bufaddr, "ALALALA", 20);
    19.  
    20.     // ...
    21. }
    22.  
    23.     VirtualProtect(CALLME, 1, PAGE_EXECUTE_READWRITE, &pr);
    24.     CALLME();
    samuraishowdown ой, не обратил внимание на твой кодес, но тож самое почти в голову пришло

    а для х64 в студии это все равно бесполезно тк там инлайн асм запрещен. проще функцию переписать на асме полностью и вытащить отдельно, чтоб например фасмом компилилась в COFF на пребилд эвенте c учетом #ifdef _WIN64 ... да и делов
     
  14. ASMatic

    ASMatic New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2010
    Сообщения:
    233
    sn0w
    и чо это за бред?
    Код (Text):
    1. void CALLME()
    2. {
    3.     char bufaddr[20];
    4.  
    5.     lstrcpyn(bufaddr, "ALALALA", 20);
    6.  
    7.     // ...
    8. }
    тож самое ток без извратов%
     
  15. sn0w

    sn0w Active Member

    Публикаций:
    0
    Регистрация:
    27 фев 2010
    Сообщения:
    958
    в твоем случае данные будут в стеке а не в теле функции.

    впрочем я еще один способ придумал тока без асма, покамест дебажу
     
  16. ASMatic

    ASMatic New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2010
    Сообщения:
    233
    sn0w
    %
    lstrcpyn(bufaddr, "ALALALA", 20);

    "ALALALA" - константа, по твоему куда её студия вкомпалит то??
     
  17. ASMatic

    ASMatic New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2010
    Сообщения:
    233
    slesh
    к стате по поводу ДВОРД-ов, я почти так и делаю обычно

    DWORD val[] = {'ulav','321e','\0'}

    тож не особо, но поудобней чем *(val+8)
     
  18. sn0w

    sn0w Active Member

    Публикаций:
    0
    Регистрация:
    27 фев 2010
    Сообщения:
    958
    ASMatic очевидно что компилер воткнет строку в секцию rdata или data, тогда как тело нашей функции находится в секции text, и нам надо прямо написать в код самой функции.

    без асма у меня вышло вот такое. можно еще eip/rip ретривнуть через CONTEXT::Eip впринципе, но решил так. пс клей не нюхал.
    Код (Text):
    1. #include <windows.h>
    2. #pragma comment(linker, "/ENTRY:start")
    3.  
    4. LPSTR   g_data_stuff;
    5.  
    6. void CALLME()
    7. {
    8.     *(DWORD*)0=0;
    9.     goto exec_code;
    10.  
    11.     GetTickCount(); // <--- g_data_stuff points there after exception
    12.     GetTickCount();  // (this is like a room for our string in function body)
    13.     GetTickCount();  //
    14.     GetTickCount(); //
    15.  
    16. exec_code:
    17.    
    18.     char rpt[128];
    19.  
    20.     lstrcpyA(g_data_stuff, "ololiolol");
    21.     wsprintf(rpt, "Address of CALLME: %08X\nAddress of buffer: %08X\nBuffer Text: %s",
    22.         CALLME, g_data_stuff, g_data_stuff);
    23.  
    24.     MessageBox(0, rpt,0,0);
    25.        
    26. }
    27.  
    28. LONG WINAPI VectoredHandler(_EXCEPTION_POINTERS *ExceptionInfo)
    29. {
    30.     // for x86
    31.  
    32.     g_data_stuff = (LPSTR)ExceptionInfo->ContextRecord->Eip;
    33.     ExceptionInfo->ContextRecord->Eip += 10; // в зависимости от длины *0 = 0
    34.  
    35.     //
    36.     // без оптимизаций у меня такой вот код генерит, поэтому +14 от экзепшна до call GetTickCount
    37.     //
    38.     //12:   *(DWORD*)0=0;
    39.     //00401003 C7 05 00 00 00 00 00 00 00 00 mov         dword ptr ds:[0],0  
    40.     //13:   goto exec_code;
    41.     //0040100D EB 1A                jmp         exec_code (401029h)  
    42.     //0040100F EB 18                jmp         exec_code (401029h)  
    43.     g_data_stuff += 14; // *0=0 + 2jmp aka goto
    44.  
    45.     return EXCEPTION_CONTINUE_EXECUTION;
    46. }
    47.  
    48. int WINAPI start()
    49. {
    50.     DWORD prot;
    51.  
    52.     VirtualProtect(CALLME, 1, PAGE_EXECUTE_READWRITE, &prot);
    53.     AddVectoredExceptionHandler(1, VectoredHandler);
    54.     CALLME();
    55.  
    56.     ExitProcess(0);
    57. }
    [​IMG]
     
  19. hamper

    hamper Member

    Публикаций:
    0
    Регистрация:
    21 ноя 2005
    Сообщения:
    37
    Адрес:
    Russia
    Если нужно, чтобы строка оказалась просто в секции .text, можно так:
    Код (Text):
    1. #pragma const_seg(".text")
    2. void func()
    3. {
    4.     const char str[]="test str";
    5. }
    Правда внутри кода func строка при этом не окажется...