Параметр псевдонима генерирует новый код, специально созданный для конкретного заданного символа, который включает в себя элементы в контексте.
Смотрим разборку:
0805c850 <_D6test564mainFZv20__T12__dgliteral1TiZ12__dgliteral1MFNbNfiZb>:
805c850: 55 push ebp
805c851: 8b ec mov ebp,esp
805c853: 83 ec 04 sub esp,0x4
805c856: 8b 48 d8 mov ecx,DWORD PTR [eax-0x28]
805c859: 3b 4d 08 cmp ecx,DWORD PTR [ebp+0x8]
805c85c: 0f 9f c0 setg al
805c85f: 0f b6 c0 movzx eax,al
805c862: c9 leave
805c863: c2 04 00 ret 0x4
Это буквальный делегат, созданный здесь (без оптимизации, кстати). Интересными строками являются mov и cmp посередине.
Обратите внимание, что указатель контекста передается делегату в регистре eax. Давайте посмотрим, как это называется:
0805c868 <_D6test5632__T4findS18main12__dgliteral1TiZ4findMFNaNbNfAiZAi>:
// snip a bunch of irrelevant code
805c870: 89 45 fc mov DWORD PTR [ebp-0x4],eax
// snip
805c892: 8b 45 fc mov eax,DWORD PTR [ebp-0x4]
805c895: 89 95 f8 ff ff ff mov DWORD PTR [ebp-0x8],edx
805c89b: e8 b0 ff ff ff call 805c850 <_D6test564mainFZv20__T12__dgliteral1TiZ12__dgliteral1MFNbNfiZb>
Обратите внимание на две вещи: во-первых, на имя: обратите внимание, что там есть dgliteral — это специально сгенерированная функция для этого конкретного аргумента!
Во-вторых, обратите внимание, что все, что было передано этой функции в eax, сохраняется и в конечном итоге также передается другой функции.
Давайте еще раз пройдемся по стеку вызовов, теперь мы находимся в _Dmain, где появляется вызов find:
805c7da: 89 e8 mov eax,ebp
805c7dc: e8 87 00 00 00 call 805c868 <_D6test5632__T4findS18main12__dgliteral1TiZ4findMFNaNbNfAiZAi>
Он передает базовый указатель! Кстати, помните, что 0x28? Мы можем видеть это и в _Dmain, пара строк:
805c7d1: c7 45 d8 fe ff ff ff mov DWORD PTR [ebp-0x28],0xfffffffe
Это строка int z = -2;
(-2 представляется как fffffffe в 32-битном формате). Он хранится в стеке как обычная локальная переменная.
Суть в том, что конкретный аргумент псевдонима генерирует совершенно новую функцию, которая знает, где находятся все локальные переменные. Когда он вызывается, ему пересылается базовый указатель на них, и это все, что ему нужно знать.
Кстати, обратите внимание, что вы также можете передавать локальные переменные в качестве параметров псевдонима и получать аналогичный код, он создает функцию, которая напрямую указывает смещение, а не берет указатель.
Кроме того, если вы попытаетесь передать делегат времени выполнения в аргумент псевдонима или попытаетесь сохранить псевдоним dg где-то еще, это не будет скомпилировано. Это специальная функция с кодом, специфичным для конкретного случая, многие общие элементы делегата не совсем работают для нее.
person
Adam D. Ruppe
schedule
13.03.2014