Принудительный inline
От: gribodemon  
Дата: 26.08.09 10:20
Оценка:
Доброго времени суток!
Пишу что-то вроде:

inline DWORD Zstrlen(PCHAR str) {
    DWORD i = 0;
    for (; str[i] != '\0'; i++);
    return i;
}
...
DWORD ln0 = Zstrlen(str0);


И получаю:


PUBLIC    ?Zstrlen@@YAKPAD@Z                ; Zstrlen
; Function compile flags: /Ogspy
;    COMDAT ?Zstrlen@@YAKPAD@Z
_TEXT    SEGMENT
_str$ = 8                        ; size = 4
?Zstrlen@@YAKPAD@Z PROC                    ; Zstrlen, COMDAT

; 330  :     DWORD i = 0;
; 331  :     for (; str[i] != '\0'; i++);

    mov    ecx, DWORD PTR _str$[esp-4]
    xor    eax, eax
    cmp    BYTE PTR [ecx], al
    je    SHORT $LN1@Zstrlen
$LL3@Zstrlen:
    inc    eax
    cmp    BYTE PTR [eax+ecx], 0
    jne    SHORT $LL3@Zstrlen
$LN1@Zstrlen:

; 332  :     return i;
; 333  : }

    ret    0
?Zstrlen@@YAKPAD@Z ENDP                    ; Zstrlen
_TEXT    ENDS

...

; 336  :     DWORD ln0 = Zstrlen(str0);

    mov    edx, DWORD PTR _str0$[esp-4]
    push    esi
    xor    esi, esi
    cmp    BYTE PTR [edx], 0
    je    SHORT $LN8@Zstrcmp
$LL10@Zstrcmp:



Как же заставить компилятор отказаться от call, от прыжков различных (je) — т.е. чтобы он вставлял код функции прямо в код, где она вызывается?
Судя по всему, префикс inline не помогает.
принудительный inline
Re: Принудительный inline
От: Eugene Sh Россия  
Дата: 26.08.09 10:32
Оценка: 2 (2)
Здравствуйте, gribodemon, Вы писали:

G>Судя по всему, префикс inline не помогает.


Вообще говоря, слово inline — лишь рекомендация для компилятора.

http://msdn.microsoft.com/en-us/library/47238hez(VS.71).aspx

The compiler treats the inline expansion options and keywords as suggestions. There is no guarantee that functions will be expanded inline. You cannot force the compiler to inline a particular function.

Re[2]: Принудительный inline
От: gribodemon  
Дата: 26.08.09 10:36
Оценка: :)
Здравствуйте, Eugene Sh, Вы писали:

ES>Здравствуйте, gribodemon, Вы писали:


G>>Судя по всему, префикс inline не помогает.


ES>Вообще говоря, слово inline — лишь рекомендация для компилятора.


ES>http://msdn.microsoft.com/en-us/library/47238hez(VS.71).aspx

ES>

ES>The compiler treats the inline expansion options and keywords as suggestions. There is no guarantee that functions will be expanded inline. You cannot force the compiler to inline a particular function.


Это я уже понял. =) Вопрос о другом — как заставить компилятор прямо вставлять код функции в то место, где она вызывается?
Re[3]: Принудительный inline
От: Alexander G Украина  
Дата: 26.08.09 10:38
Оценка: 1 (1)
Здравствуйте, gribodemon, Вы писали:

G>Это я уже понял. =) Вопрос о другом — как заставить компилятор прямо вставлять код функции в то место, где она вызывается?


Зависит от компилятора, для MSVC __forceinline, но и оно не гарантирует.
Русский военный корабль идёт ко дну!
Re[4]: Принудительный inline
От: gribodemon  
Дата: 26.08.09 10:44
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Зависит от компилятора, для MSVC __forceinline, но и оно не гарантирует.


Угумс, у меня MSVC. Но __forceinline даже в моём примере не помогло. =(
Re[3]: Принудительный inline
От: quodum  
Дата: 26.08.09 10:48
Оценка: 1 (1)
Здравствуйте, gribodemon, Вы писали:

ES>>

ES>>You cannot force the compiler to inline a particular function.


G>Это я уже понял. =) Вопрос о другом — как заставить компилятор прямо вставлять код функции в то место, где она вызывается?


— Мы сами знаем, что она не имеет решения, — сказал Хунта, немедленно ощетиниваясь. — Мы хотим знать, как её решать.




У MSVC есть __forceinline. По ссылке, в числе прочего, можно найти перечень случаев, когда даже такая функция не будет встроена.
Re: Принудительный inline
От: Сергей Мухин Россия  
Дата: 26.08.09 10:57
Оценка: 1 (1)
Здравствуйте, gribodemon, Вы писали:


G>; 336 : DWORD ln0 = Zstrlen(str0);


G> mov edx, DWORD PTR _str0$[esp-4]

G> push esi
G> xor esi, esi
G> cmp BYTE PTR [edx], 0
G> je SHORT $LN8@Zstrcmp
G>$LL10@Zstrcmp:
G>[/asm]


G>Как же заставить компилятор отказаться от call, от прыжков различных (je) — т.е. чтобы он вставлял код функции прямо в код, где она вызывается?

G>Судя по всему, префикс inline не помогает.

1. хотелось бы опции знать и какой компилятор (версия тоже)
2. в приведенном ассемблере НЕТ вызова ф-ии Zstrlen. Так что покажите полностью
3. про inline и _foreinline все уже сказали правильно
---
С уважением,
Сергей Мухин
Re: Принудительный inline
От: Bell Россия  
Дата: 26.08.09 11:08
Оценка: 1 (1) +1
Здравствуйте, gribodemon, Вы писали:

На всякий случай: приведенный ассемблерный код получен при сборке Release-версии? Если да, то какие опции оптимизации используются?

ЗЫ
MSVC 7.1, Release, /O2, /Ob2, /Ot заинлайнил функцию ьез проблем.
Любите книгу — источник знаний (с) М.Горький
Re[2]: Принудительный inline
От: gribodemon  
Дата: 26.08.09 11:11
Оценка: :)
Здравствуйте, Сергей Мухин, Вы писали:

СМ>1. хотелось бы опции знать и какой компилятор (версия тоже)

CL.EXE
      CompanyName    : Microsoft Corporation
      FileDescription    : Microsoft® C/C++ Compiler Driver
      FileVersion    : 14.00.50727.42 (RTM.050727-4200)
      InternalName    : CL.EXE
      LegalCopyright    : © Microsoft Corporation.  All rights reserved.
      OriginalFilename    : CL.EXE
      ProductName    : Microsoft® Visual Studio® 2005
      ProductVersion    : 8.00.50727.42


Вообще, не очень хотелось бы получить решение, зависящее от версии компилятора.

СМ>2. в приведенном ассемблере НЕТ вызова ф-ии Zstrlen. Так что покажите полностью

Ну, там же прыжок на эту функцию (JE)

СМ>3. про inline и _foreinline все уже сказали правильно

Ну да, видимо, проблема в настройках оптимизации моего проекта.
Re[2]: Принудительный inline
От: gribodemon  
Дата: 26.08.09 11:12
Оценка:
Здравствуйте, Bell, Вы писали:

B>На всякий случай: приведенный ассемблерный код получен при сборке Release-версии? Если да, то какие опции оптимизации используются?


B>ЗЫ

B>MSVC 7.1, Release, /O2, /Ob2, /Ot заинлайнил функцию ьез проблем.

Угумс, это был Release.
Так и есть — дело в настройках проекта.
Re: Принудительный inline
От: Tilir Россия http://tilir.livejournal.com
Дата: 26.08.09 11:13
Оценка: 1 (1)
Здравствуйте, gribodemon, Вы писали:

G>Как же заставить компилятор отказаться от call, от прыжков различных (je) — т.е. чтобы он вставлял код функции прямо в код, где она вызывается?


Рассмотрите вариант заменить функцию на макрос.
Re: Принудительный inline
От: Pzz Россия https://github.com/alexpevzner
Дата: 26.08.09 11:14
Оценка: +1
Здравствуйте, gribodemon, Вы писали:

G>Как же заставить компилятор отказаться от call, от прыжков различных (je) — т.е. чтобы он вставлял код функции прямо в код, где она вызывается?

G>Судя по всему, префикс inline не помогает.

Насколько я понял, из приведенного вами обрывка ассемблерного текста, компилятор сделал две вещи: 1) на всякий случай сгенерировал вам Zstrlen() как нормальную функцию (ну типа, вдруг вам захочется на нее указатель получить, он же не знает) 2) вставил таки ее содержимое по месту вызова. Сама функция содержит цикл, а поэтому содержит переходы. В точке вызова содержится переход в "правильное" место этого цикла.

Первое вас не должно особо волновать, если только из экономии места в объектном файле (насколько я помню, мелкософтовский линкер достаточно умный, и неиспользованные символы из объектного файла не попадают в исполняемый файл).
Re[3]: Принудительный inline
От: K13 http://akvis.com
Дата: 26.08.09 11:16
Оценка:
СМ>>2. в приведенном ассемблере НЕТ вызова ф-ии Zstrlen. Так что покажите полностью
G>Ну, там же прыжок на эту функцию (JE)

НЕТУ. смотрим внимательно! и приводим листинг полностью!
судя по имени метки, переход внутри функции Zstrcmp а не на Zstrlen.
Re: Принудительный inline
От: mefrill Россия  
Дата: 26.08.09 11:22
Оценка:
Здравствуйте, gribodemon, Вы писали:

G>Как же заставить компилятор отказаться от call, от прыжков различных (je) — т.е. чтобы он вставлял код функции прямо в код, где она вызывается?

G>Судя по всему, префикс inline не помогает.

А там точно определение функции известно компилятору на момент разбора места, где эта функция вызывается?
Re[3]: Принудительный inline
От: Сергей Мухин Россия  
Дата: 26.08.09 11:30
Оценка: +1
Здравствуйте, gribodemon, Вы писали:

G>Здравствуйте, Сергей Мухин, Вы писали:


СМ>>1. хотелось бы опции знать и какой компилятор (версия тоже)


G>Вообще, не очень хотелось бы получить решение, зависящее от версии компилятора.

inline зависит от компилятора и от версии и от опций

СМ>>2. в приведенном ассемблере НЕТ вызова ф-ии Zstrlen. Так что покажите полностью

G>Ну, там же прыжок на эту функцию (JE)

JE — это переход если условие равно. Обычно это не является вызовом ф-ии.

СМ>>3. про inline и _foreinline все уже сказали правильно

G>Ну да, видимо, проблема в настройках оптимизации моего проекта.

Зачем Вам переписывать стандартные фии? Зачем лезть в ассемблер, если не понимаете в нем? Стандартная strlen вполне быстра.
---
С уважением,
Сергей Мухин
Re[4]: Принудительный inline
От: gribodemon  
Дата: 26.08.09 13:05
Оценка:
Здравствуйте, Сергей Мухин, Вы писали:

СМ>JE — это переход если условие равно. Обычно это не является вызовом ф-ии.


Да знаю я для чего нужна эта инструкция.
Проблема в другом. Я хочу чтобы мой код был переносим в память другого процесса.
Т.е. я хочу взять адрес своей функции, записать её в память другого процесса, передать управление этому коду через функцию создания удалённых потоков.
Для этого в моём коде не должно быть таких вот (JE) инструкций. Поэтому я и хочу чтобы компилятор просто взял код моей функции и вставил её на место вызова.
Т.е. на выходе я хочу получить что-то вроде shellcode.

СМ>Зачем Вам переписывать стандартные фии?

up

СМ>Зачем лезть в ассемблер, если не понимаете в нем?

Ваше выражение можно упросить до:
"Зачем что-то изучать, если ты это ещё не изучил?"

И вообще — зачем разводить offtopic?

СМ>Стандартная strlen вполне быстра.

В этом случае, мой код будет зависим от библиотеки msvcrt.dll и вообще — от адресов функций в этой библиотеке.
up
Re[5]: Принудительный inline
От: Сергей Мухин Россия  
Дата: 26.08.09 13:09
Оценка:
Здравствуйте, gribodemon, Вы писали:

G>Здравствуйте, Сергей Мухин, Вы писали:


СМ>>JE — это переход если условие равно. Обычно это не является вызовом ф-ии.


G>Да знаю я для чего нужна эта инструкция.

G>Проблема в другом. Я хочу чтобы мой код был переносим в память другого процесса.

поищите, это тема недавно обсуждалась

G>Т.е. я хочу взять адрес своей функции, записать её в память другого процесса, передать управление этому коду через функцию создания удалённых потоков.

G>Для этого в моём коде не должно быть таких вот (JE) инструкций. Поэтому я и хочу чтобы компилятор просто взял код моей функции и вставил её на место вызова.


ну он так и сделал, Вам стало легче?

а JE как раз не мешает переносу, ибо имеет относительный адрес.

G>Т.е. на выходе я хочу получить что-то вроде shellcode.


СМ>>Зачем Вам переписывать стандартные фии?

G>up

СМ>>Зачем лезть в ассемблер, если не понимаете в нем?

G>Ваше выражение можно упросить до:
G>"Зачем что-то изучать, если ты это ещё не изучил?"

Вы не правильно поставили задачу. Из-за этого и проблемы.

G>И вообще — зачем разводить offtopic?


СМ>>Стандартная strlen вполне быстра.

G>В этом случае, мой код будет зависим от библиотеки msvcrt.dll и вообще — от адресов функций в этой библиотеке.
G>up
---
С уважением,
Сергей Мухин
Re[4]: Принудительный inline
От: gribodemon  
Дата: 26.08.09 13:24
Оценка:
Здравствуйте, K13, Вы писали:

СМ>>>2. в приведенном ассемблере НЕТ вызова ф-ии Zstrlen. Так что покажите полностью

G>>Ну, там же прыжок на эту функцию (JE)

K13>НЕТУ. смотрим внимательно! и приводим листинг полностью!

K13>судя по имени метки, переход внутри функции Zstrcmp а не на Zstrlen.

М... фиг знает. Из OllyDebugger'а для ясности достал финальный код.


CPU Disasm
Address   Hex dump          Command                                  Comments
00401000  /. 8B5424 04      MOV EDX,DWORD PTR SS:[ARG.1]
00401004     56             PUSH ESI
00401005     33F6           XOR ESI,ESI
00401007     803A 00        CMP BYTE PTR DS:[EDX],0
0040100A     74 07          JE SHORT Project.00401013
0040100C     46             INC ESI
0040100D     803C16 00      CMP BYTE PTR DS:[EDX+ESI],0
00401011     75             DB 75                                    ; CHAR 'u'
00401012   . F98B4424       DD 24448BF9
00401016     0C             DB 0C                                    ; Form Feed
00401017  /. 33C9           XOR ECX,ECX
00401019  \. 3808           CMP BYTE PTR DS:[EAX],CL
0040101B     74             DB 74                                    ; CHAR 't'
0040101C     07             DB 07
0040101D     41             DB 41                                    ; CHAR 'A'
0040101E     80             DB 80
0040101F     3C 01          CMP AL,1


Я вот про это: JE SHORT Project.00401013
Вот это привязано к конкретному адресу. Вот это меня и беспокоило.
Спасибо за помощь. =)
Re[5]: Принудительный inline
От: Аноним  
Дата: 26.08.09 13:25
Оценка: +1 -1
СМ>>JE — это переход если условие равно. Обычно это не является вызовом ф-ии.
G>Да знаю я для чего нужна эта инструкция.
G>Проблема в другом. Я хочу чтобы мой код был переносим в память другого процесса.
G>Т.е. я хочу взять адрес своей функции, записать её в память другого процесса, передать управление этому коду через функцию создания удалённых потоков.
G>Для этого в моём коде не должно быть таких вот (JE) инструкций. Поэтому я и хочу чтобы компилятор просто взял код моей функции и вставил её на место вызова.
G>Т.е. на выходе я хочу получить что-то вроде shellcode.
Вы не получите гарантированный код который будет компиляться в рабочий шеллкод
Пишите на асме. Это здесь оправдано
Re[5]: Принудительный inline
От: Сергей Мухин Россия  
Дата: 26.08.09 13:41
Оценка: 2 (1)
Здравствуйте, gribodemon, Вы писали:


G>Я вот про это: JE SHORT Project.00401013

G>Вот это привязано к конкретному адресу. Вот это меня и беспокоило.

почитайте что-нибудь про ассемблер сначала. у команды Jcc НЕТ привязки к конкретному адресу, она содержит смещение относительно своего конца. Что можно посмотреть собственно в коде (74 07)
---
С уважением,
Сергей Мухин
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.