GCC inline assembly guide | ||
---|---|---|
ÀÌÀü | 3Àå. Applications |
Stack »ç¿ë·®À» ¾î´À Á¤µµ ÀÌÇÏ·Î º¸ÀåÇϱâ À§Çؼ ¾î¶² ±â´ÉµéÀº stackÀ» ¹Ù²Ù¾î °¡¸é ½ÇÇàÇÏ´Â °æ¿ì°¡ ÀÖ½À´Ï´Ù. ¿¹¸¦ µé¾î, OS¿¡¼ interrupt handler¿Í ±×¿¡ µû¶ó ½ÇÇàµÇ´Â bottom half handlerµéÀÇ °æ¿ì interrupt ¹ß»ý½ÃÀÇ kernel stack¿¡¼ ½ÇÇàµÈ´Ù¸é interrupt nesting µîÀ» »ý°¢ÇÒ ¶§ ¸ðµç kernel threadÀÇ stack Å©±â°¡ ²Ï Ä¿Á®¾ß Çϴµ¥´Ù°¡ ÇÊ¿äÇÑ Å©±â¸¦ Á¤È®È÷ ¾Ë±âµµ Èûµì´Ï´Ù.
¾Æ·¡ÀÇ ÇÁ·Î±×·¥¿¡¼ call_with_stack_switch´Â funcaddr·Î ÁÖ¾îÁø ÇÔ¼ö¸¦ arg¸¦ ÀÎÀÚ·Î ÇØ¼ altstack¿¡¼ ¼öÇàÇÏ°í ±× °á°ú°ªÀ» µ¹·ÁÁÝ´Ï´Ù.
#include <stdio.h> #define fetch_esp(_esp) \ __asm__ __volatile__("movl %%esp, %0" : "=g" (*_esp)) static __inline__ int call_with_stack_switch(void *funcaddr, unsigned int arg, void *altstack) { int a, b, c, d, D, S; __asm__ __volatile__( "pushl %%ebp \n\t" "movl %%esp, %%eax \n\t" "movl %8, %%esp \n\t" "pushl %%eax \n\t" "pushl %7 \n\t" "call *%6 \n\t" "addl $4, %%esp \n\t" "popl %%esp \n\t" "popl %%ebp " : "=&a" (a), "=b" (b), "=c" (c), "=d" (d), "=D" (D), "=S" (S) : "r" (funcaddr), "ri" (arg), "ri" (altstack)); return a; } static int say_hello(unsigned int arg) { unsigned esp; fetch_esp(&esp); printf("say_hello : hello world... esp=%08x, arg=%d\n", esp, arg); arg *= arg; printf("say_hello : returning %d\n", arg); return arg; } static char _altstack[8192]; static void *altstack = _altstack + sizeof(_altstack); int main(void) { unsigned esp; int rv, arg = 1096; fetch_esp(&esp); printf("main : current esp=%08x, altstack=%08p-%08p\n", esp, _altstack, altstack); printf("main : calling say_hello w/ stack switch (arg=%d)\n", arg); rv = call_with_stack_switch(say_hello, arg, altstack); fetch_esp(&esp); printf("main : esp=%08x, arg=%d, rv=%d\n", esp, arg, rv); return 0; } |
call_with_stack_switch¿¡¼ 6°³ÀÇ º¯¼ö°¡ ¼±¾ðµÇ¾î Àִµ¥ ÀÌ º¯¼öµéÀº ¸ðµÎ ·¹Áö½ºÅ͵éÀÇ outputÀ¸·Î ¾²ÀÔ´Ï´Ù. a:eax, b:ebx, c:ecx, d:edx, D:edi, S:edi·Î ´ëÀÀÀÌ µË´Ï´Ù. a¿Ü¿¡´Â outputÀ̶ó°í Á¤ÀÇµÈ ÈÄ ¾²ÀÌÁö ¾Ê´Âµ¥, ´ÜÁö ±× ·¹Áö½ºÅ͵éÀÇ °ªÀÌ ¹Ù²ï´Ù´Â °ÍÀ» ÄÄÆÄÀÏ·¯¿¡°Ô ¾Ë·ÁÁÖ´Â ¿ªÈ°¸¸À» ÇϰԵ˴ϴÙ. Clobber list¿Í °ÅÀÇ °°Àº ±â´ÉÀ̶ó°í ÇÒ ¼ö ÀÖÁö¸¸ clobber·Î ÁöÁ¤µÈ ·¹Áö½ºÅÍ´Â input, output ¾î´À°ÍÀ¸·Îµµ ¾²ÀÏ ¼ö ¾ø°í À§ÀÇ inline assembly¿¡ ÀÖ´Â ¼¼°³ÀÇ input º¯¼öµéÀÌ ±× ·¹Áö½ºÅÍ·Î ÇÒ´çµÉ ¼ö ¾ø°ÔµË´Ï´Ù. Áï, dummy º¯¼ö¸¦ ½á¼ outputÀ¸·Î Á¤ÇØÁÖ°Ô µÇ¸é 'inputÀ¸·Î ÇÒ´çµÉ ¼ö ÀÖÁö¸¸ °á°úÀûÀ¸·Î °ªÀº º¯ÇÑ´Ù'¶ó´Â ¶æÀÔ´Ï´Ù.
°¢ ¶óÀÎÀ» »ìÆìº¸µµ·Ï ÇϰڽÀ´Ï´Ù.
1: pushl %%ebp |
inline assemblyÀÇ ¾Õ°ú ³¡¿¡¼ ebp¸¦ ÀúÀåÇÏ°í º¹±¸Çϴµ¥ ebp´Â ix86¿¡¼ frame pointer·Î ¾²ÀÔ´Ï´Ù. ¸¸¾à -fomit-frame-pointer ¿É¼ÇÀ» ÁÖÁö¾Ê°í ÄÄÆÄÀÏÇϸé frame pointerÀÇ °ü¸®°¡ ÇÔ¼ö entry/exit¿¡¼ µÇ¾î ½Å°æ ¾µ Çʿ䰡 ¾øÁö¸¸ frame pointer¸¦ »ý·«ÇÏ°Ô µÇ¸é ÄÄÆÄÀÏ·¯°¡ ebp¸¦ ´Ù¸¥ ¿ëµµ·Î ¾²°ÔµË´Ï´Ù. ÇÏÁö¸¸ gcc¿¡°Ô ebp°¡ º¯ÇÔÀ» ¾Ë·ÁÁÙ ¹æ¹ýÀÌ ¾ø±â¶§¹®¿¡ ÄÄÆÄÀÏ·¯°¡ ¸ð¸£´Â ü·Î ebpÀÇ °ªÀÌ ¹Ù²î¾î ¹ö¸± ¼ö°¡ ÀÖ½À´Ï´Ù. µû¶ó¼ ´Ù¸¥ ·¹Áö½ºÅ͵é°ú ´Þ¸® µû·Î ÀúÀå/º¹±¸ ÇØ ÁÙ Çʿ䰡 ÀÖ½À´Ï´Ù.
ebp¿Í gcc¿¡ ´ëÇØ Á¶±Ý ´õ ¼³¸íÇϰڽÀ´Ï´Ù. ebp´Â ¿ÏÀüÇÑ ¹ü¿ë ·¹Áö½ºÅÍ´Â ¾Æ´ÏÁö¸¸ ´ëºÎºÐÀÇ ÁÖ¼Ò°è»ê¿¡ »ç¿ëµÉ ¼ö ÀÖ°í °ªµéÀ» Àá½Ã ÀúÀåÇÏ´Â Àå¼Ò·Îµµ »ç¿ëµÉ ¼ö ÀÖ½À´Ï´Ù. gcc´Â frame pointer·Î ¾²Áö ¾ÊÀ» ¶§ ebp¸¦ ÀÌ·± ¿ëµµ·Î »ç¿ëÇÏÁö¸¸ input/output¿¡¼ Á÷Á¢ ebp¸¦ ÁöÁ¤ÇØÁÙ ¼ö ÀÖ´Â ¹æ¹ýÀÌ ¾ø°í, clobber list¿¡¼ ÁöÁ¤À» ÇÒ ¼ö ÀÖÁö¸¸ ¹«½ÃµÇ±â¶§¹®¿¡ inline assembly¿¡¼ ebpÀÇ °ªÀ» º¯È½Ãų ¶§´Â ¹Ýµå½Ã ÀúÀå/º¹±¸ ÇØÁÖ¾î¾ß ÇÕ´Ï´Ù. GccÀÇ ¹ö±×¶ó°íµµ ÇÒ ¼ö ÀÖ½À´Ï´Ù.
2: movl %%esp, %%eax |
ÇöÀç esp°ªÀ» eax¿¡ ÀúÀåÇÕ´Ï´Ù. altstackÀ¸·Î ¹Ù²Ù¾î ÇÔ¼ö¸¦ ½ÇÇàÇÏ°í ¿ø·¡ÀÇ stackÀ¸·Î µ¹¾Æ¿Í¾ßÇϱ⠶§¹®¿¡ ¿ø·¡ stack pointer¸¦ ±â¾ïÇϰí ÀÖ¾î¾ß ÇÕ´Ï´Ù. À̸¦ altstackÀ¸·Î ¹Ù²Ù°í Á¦ÀÏ Ã³À½¿¡ pushÇϱâ À§ÇØ eax¿¡ ÀúÀåÇØ µÎ´Â °ÍÀÔ´Ï´Ù.
3: movl %8, %%esp |
%8Àº altstackÀÔ´Ï´Ù. altstackÀ¸·Î stackÀ» ¹Ù²ß´Ï´Ù.
4: pushl %%eax |
¿ø·¡ÀÇ stack pointer¸¦ stack¿¡ ÀúÀåÇÕ´Ï´Ù.
5: pushl %7 |
%7Àº argÀÔ´Ï´Ù. ÇÔ¼ö È£ÃâÀ» À§ÇØ arg¸¦ »õ·Î ¹Ù²ï stack¿¡ pushÇÕ´Ï´Ù.
6: call *%6 |
funcaddrÀ» È£ÃâÇÕ´Ï´Ù. *´Â indirect callÀÓÀ» ³ªÅ¸³À´Ï´Ù. Input¿¡¼ ´õ ÀÚ¼¼È÷ ¼³¸íÇϰڽÀ´Ï´Ù.
7: addl $4, %%esp |
funcaddrÀÇ ½ÇÇàÀÌ ³¡³µÀ¸¹Ç·Î arg¸¦ ¾ø¾Û´Ï´Ù.
8: popl %%esp |
¿ø·¡ÀÇ stackÀ¸·Î µ¹¾Æ¿É´Ï´Ù.
9: popl %%ebp |
1¿¡¼ ÀúÀåÇØµÐ ebp¸¦ º¹±¸ÇÕ´Ï´Ù.
Output¿¡¼ a°¡ early clobber·Î ÁöÁ¤µÈ °Í À̿ܿ¡´Â Ưº°ÇÑ Á¡ÀÌ ¾ø½À´Ï´Ù. eax¸¦ Á¦¿ÜÇÑ ·¹Áö½ºÅ͵éÀº funcaddrÀÇ ÇÔ¼ö°¡ ½ÇÇàÇÏ¸é¼ Áï, ¸ðµç inputÀÌ ´Ù ¾²ÀÎ ÈÄ¿¡ ¹Ù²ð ¼ö Àֱ⠶§¹®¿¡ early clobber·Î ÁöÁ¤ÇÒ Çʿ䰡 ¾ø°í µû¶ó¼ input¿¡ ÇÒ´çµÉ ¼ö ÀÖ½À´Ï´Ù.
Input¿¡¼ funcaddrÀº ¹ü¿ë ·¹Áö½ºÅÍ, arg¿Í altstackÀº ¹ü¿ë ·¹Áö½ºÅÍ ¶Ç´Â immediate constraint¸¦ °¡Áö°í ÀÖ½À´Ï´Ù. Memory operand´Â esp¿¡ ´ëÇÑ offset addressingÀ¸·Î Ç¥ÇöµÉ ¼ö ÀÖ°í, esp¸¦ ¹Ù²Û ÈÄ¿¡ inputµéÀ» »ç¿ëÇϱ⠶§¹®¿¡ memory operand´Â Çô¿ëÇÒ ¼ö ¾øÀ¸¹Ç·Î ·¹Áö½ºÅͳª immediateÀ» »ç¿ëÇØ¾ß Çϴµ¥ ix86ÀÇ call instructionÀº immediate operand·Î´Â relative call¹Û¿¡ Áö¿øÇÏÁö ¾Ê±â ¶§¹®¿¡ indirect callÀ» ÇØ¾ßÇÏ°í µû¶ó¼ 'r' constraint¸¦ ½á¾ßÇÕ´Ï´Ù. ³ª¸ÓÁö µÑÀº immediateÀ̾ °ü°è°¡ ¾ø±â ¶§¹®¿¡ 'ri' constraint¸¦ °¡Áö°í ÀÖ½À´Ï´Ù.
arg¿Í altstackÀÌ call_with_stack_switchÀÇ ÀÎÀÚÀ̱⠶§¹®¿¡ immediateÀÌ Àǹ̾ø´Ù°í »ý°¢ÇÒ ¼öµµ ÀÖÁö¸¸, __inline__À¸·Î ¼±¾ðµÇ¾î Àֱ⠶§¹®¿¡ ÀÎÀÚ°¡ compile time¿¡ °áÁ¤µÉ ¼ö ÀÖÀ¸¸é immediateÀÌ µË´Ï´Ù. ¾Æ·¡ÀÇ ÄÄÆÄÀÏÇÑ assembly¸¦ º¸¸é ¾Ë ¼ö ÀÖ½À´Ï´Ù.
.file "call_with_stack_switch.c" .version "01.01" gcc2_compiled.: .section .rodata .align 32 .LC0: .string "say_hello : hello world... esp=%08x, arg=%d\n" .LC1: .string "say_hello : returning %d\n" .text .align 4 .type say_hello,@function say_hello: subl $4,%esp pushl %ebx movl 12(%esp),%ebx #APP movl %esp, 4(%esp) #NO_APP pushl %ebx pushl 8(%esp) pushl $.LC0 call printf imull %ebx,%ebx pushl %ebx pushl $.LC1 call printf movl %ebx,%eax addl $20,%esp popl %ebx popl %ecx ret .Lfe1: .size say_hello,.Lfe1-say_hello .data .align 4 .type altstack,@object .size altstack,4 altstack: .long _altstack+8192 .section .rodata .align 32 .LC2: .string "main : current esp=%08x, altstack=%08p-%08p\n" .align 32 .LC3: .string "main : calling say_hello w/ stack switch (arg=%d)\n" .align 32 .LC4: .string "main : esp=%08x, arg=%d, rv=%d\n" .text .align 4 .globl main .type main,@function main: subl $4,%esp pushl %ebp pushl %edi pushl %esi pushl %ebx #APP movl %esp, 16(%esp) #NO_APP pushl altstack pushl $_altstack pushl 24(%esp) pushl $.LC2 call printf pushl $1096 pushl $.LC3 call printf movl $say_hello,%edx movl altstack,%eax addl $24,%esp movl %eax,%ebp #APP pushl %ebp movl %esp, %eax movl %ebp, %esp pushl %eax pushl $1096 call *%edx addl $4, %esp popl %esp popl %ebp movl %esp, 16(%esp) #NO_APP pushl %eax pushl $1096 pushl 24(%esp) pushl $.LC4 call printf xorl %eax,%eax addl $16,%esp popl %ebx popl %esi popl %edi popl %ebp popl %ecx ret .Lfe2: .size main,.Lfe2-main .local _altstack .comm _altstack,8192,32 .ident "GCC: (GNU) 2.95.4 20010902 (Debian prerelease)" |
call_with_stack_switch°¡ main¾È¿¡ inlining µÇ¾ú°í, altstackÀÌ %ebp·Î, arg´Â immediate operand·Î, funcaddrÀÌ %edx·Î ÇÒ´çµÈ °ÍÀ» º¼ ¼ö ÀÖ½À´Ï´Ù. ¶Ç, Dummy º¯¼öµéÀº ¸ðµÎ »ç¶óÁ³°í, return °ªÀÎ aµµ %eax¿¡ ÀÖ´Â ±×´ë·Î »ç¿ëµÇ°í ÀÖ½À´Ï´Ù.
À§ÀÇ ÇÁ·Î±×·¥À» ½ÇÇàÇÏ¸é ´ÙÀ½°ú °°Àº °á°ú°¡ ³ª¿É´Ï´Ù.
% ./call_with_stack_switch main : current esp=bffffc3c, altstack=0x80497c0-0x804b7c0 main : calling say_hello w/ stack switch (arg=1096) say_hello : hello world... esp=0804b7ac, arg=1096 say_hello : returning 1201216 main : esp=bffffc3c, arg=1096, rv=1201216 |
Inline assembly¸¦ »ç¿ëÇÒ ¶§´Â ·¹Áö½ºÅÍ ÇÒ´çÀÌ Á¤È®È÷ ¾î¶»°Ô µÇ´ÂÁö ÇÁ·Î±×·¥À» ¾²¸é¼´Â ¾Ë ¼ö ¾ø°í, ƯÈ÷ early clobber ¿É¼ÇÀº ÀرⰡ ½±°í À߸øµÇ¾úÀ» ¶§ ã±â°¡ »ó´çÈ÷ Èûµé±â ¶§¹®¿¡ Á¦´ë·Î ÀÛµ¿ÇÏ´Â °Í °°´õ¶óµµ -S ¿É¼ÇÀ» ÁÖ¾î ¿øÇÏ´Â Äڵ尡 »ý¼ºµÇ¾ú´ÂÁö¸¦ È®ÀÎÇØº¸´Â °ÍÀÌ ÁÁ½À´Ï´Ù.