| 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 ¿É¼ÇÀ» ÁÖ¾î ¿øÇÏ´Â Äڵ尡 »ý¼ºµÇ¾ú´ÂÁö¸¦ È®ÀÎÇØº¸´Â °ÍÀÌ ÁÁ½À´Ï´Ù.