GCC inline assembly guide 2001³â 10¿ù 4ÀÏ Çã ÅÂÁØ ¾Æ¶ó±â¼ú 0.1 2001-10-04 tj ÃÖÃÊÀÛ¼º ÀÌ ¹®¼­´Â gcc¿¡¼­ inline assembly¸¦ ¼³¸íÇÕ´Ï´Ù. ¼³¸íÀ̳ª ¿¹Á¦´Â ¸ðµÎ ix86À» ±âÁØÀ¸·Î ÇÏ¸ç ¾²ÀÌ´Â ¾ð¾î´Â cÀÔ´Ï´Ù. GCC manual°ú linux/freeBSD source ¹× ÀÚ½ÅÀÇ °æÇèÀ» ¹ÙÅÁÀ¸·Î ½è½À´Ï´Ù. »ç¿ë¹æ¹ýÁ¤µµÀÇ ¼³¸íº¸´Ù´Â »ç¿ë¿¹¿Í ÀÀ¿ëµéÀ» º¸¿©ÁÖ°í ¼³¸íÇÏ´Â °ÍÀ» ¸ñÇ¥·ÎÇÕ´Ï´Ù. ÀÌ ¹®¼­¸¦ ÀбâÀ§Çؼ­´Â C¸¦ ´É¼÷ÇÏ°Ô ´Ù·ê ¼ö ÀÖÀ¸¸ç processor(ix86)¿Í assembly¿¡ ´ëÇØ ¾î´ÀÁ¤µµ´Â ¾Ë°í ÀÖ¾î¾ß ÇÕ´Ï´Ù. (todo: ·¹ÆÛ·±½º) ÀÌ ¹®¼­ÀÇ ÃֽŠ¹öÀüÀº ÀÌ°÷ ¿¡¼­ ±¸ÇÒ ¼ö ÀÖÀ¸¸ç Ʋ¸° Á¡ ÁöÀû, Á¦¾È, Áú¹®µîÀº ¿©±â ¿¡ ÇϽñ⠹ٶø´Ï´Ù. ¼­¹®
Ã¥ÀÓÀÇ ÇÑ°è º» ÀúÀÚ´Â ¹®¼­ÀÇ ³»¿ëÀÌ ¾ß±âÇÒ ¼ö ÀÖ´Â ¾î¶°ÇÑ °á°ú¿¡ ´ëÇؼ­µµ Ã¥ÀÓÀ» ÁöÁö ¾Ê½À´Ï´Ù. º» ¹®¼­¿¡¼­ ³»Æ÷ÇÏ°í ÀÖ´Â Á¤º¸µé ¹× ¿¹Á¦µéÀº ¿©·¯ºÐÀÌ ¾Ë¾Æ¼­ È°¿ëÇϽʽÿÀ. ºñ·Ï ÃÖ¼±À» ´ÙÇßÀ¸³ª ÀÌ ¹®¼­´Â Ʋ¸° Á¡À̳ª ¿À·ù°¡ ÀÖÀ» ¼öµµ ÀÖ½À´Ï´Ù. ¸¸¾à ¿©·¯ºÐÀÌ Æ²¸° Á¡À» ¹ß°ßÇß´Ù¸é ²À Àú¿¡°Ô ¾Ë·Á Áֽñ⠹ٶø´Ï´Ù.
Inline assembly? System programmingÀ» Çϰųª ¼º´ÉÀÌ Áß¿äÇÑ ÇÁ·Î±×·¥ÀÇ tight loopÀ» © ¶§ assembly¸¦ ½á¾ßÇÏ´Â °æ¿ì°¡ »ý±é´Ï´Ù. Áï, ÇÁ·Î±×·¥ÀÇ ´ëºÎºÐÀ» C³ª C++µîÀ¸·Î ¸¸µé°í °í±Þ¾ð¾î·Î´Â ÇÒ ¼ö ¾ø°Å³ª, ±× ºÎºÐÀ» assembly·Î ½á¼­ ¼Óµµ Çâ»óÀÌ °¡´ÉÇÒ ¶§ ±× ºÎºÐ¸¸À» assembly·Î ¸¸µé¾î¼­ C·Î (C/C++ ¸ðµÎ Àû¿ëµÇÁö¸¸ ¾ÕÀ¸·Î´Â ±×³É C¶ó°í¸¸ ÇÏ°Ú½À´Ï´Ù) ¸¸µç ³ª¸ÓÁö ºÎºÐ°ú °°ÀÌ ¾²°Ô µË´Ï´Ù. C·Î µÈ ºÎºÐ°ú assembly·Î µÈ ºÎºÐÀ» °°ÀÌ µ¿ÀÛ½ÃÅ°´Â µ¥´Â Å©°Ô µÎ °¡Áö ¹æ¹ýÀÌ Àִµ¥ Çϳª´Â assmbly·Î ¾´ ºÎºÐÀ» µ¶¸³µÈ ÇÔ¼ö·Î ¸¸µé¾î µû·Î ¾î¼Àºí ÇÑ ÈÄ¿¡ ¿ÀºêÁ§Æ® È­ÀÏÀ» ¸µÅ©½ÃÅ°´Â ¹æ¹ýÀÌ ÀÖ°í, ³ª¸ÓÁö Çϳª´Â inline assembly¸¦ ¾²´Â ¹æ¹ýÀÌ ÀÖ½À´Ï´Ù. µû·Î assemblyÈ­ÀÏÀ» ¸¸µé¸é CÀÇ ÇÔ¼öÈ£Ãâ¹æ½Ä¿¡ ¸ÂÃß¾î ÇÔ¼öÀÇ entry¿Í exit¿¡¼­ ÀÎÀÚµéÀ» ¹Þ°í return°ªÀ» µ¹·ÁÁÖ´Â ºÎºÐ¸¸ ½Å°æ¾²¸é µË´Ï´Ù. gcc(gasm)¿ÜÀÇ nasm °°Àº ´Ù¸¥ assembler¸¦ ¾µ ¼öµµ ÀÖÀ¸¹Ç·Î ¾î´ÀÁ¤µµ Å©±â°¡ µÇ´Â ºÎºÐÀ» assembly·Î ÀÛ¼ºÇÒ ¶§´Â ÀÌ ¹æ¹ýÀ» ¾²´Â °ÍÀÌ ÁÁ½À´Ï´Ù. ÇÏÁö¸¸ ¸¹Àº °æ¿ì¿¡ Àüü ·ÎÁ÷ÀÇ ±ØÈ÷ ÀϺκп¡¼­¸¸ assembly°¡ ÇÊ¿äÇÏ°í ƯÈ÷ compiler°¡ »ç¿ëÇÏÁö ¸øÇÏ´Â processorÀÇ Æ¯Á¤ÇÑ ±â´ÉÀ» ¾²±âÀ§ÇØ assembly¸¦ ¾µ ¶§´Â Àû°Ô´Â ¸î°³, ¸¹¾Æµµ ÀÌ»ï½Ê°³ Á¤µµÀÇ instruction¸¸À» assembly·Î ¸¸µé¸é µÇ´Â °æ¿ì°¡ ´ëºÎºÐÀÌ°í À̸¦ À§Çؼ­ µû·Î ÇÔ¼ö¸¦ ¸¸µé¾î ¸µÅ©ÇÏ´Â °ÍÀº ¹ø°Å·Î¿îµ¥´Ù°¡ ÀÚÁÖ È£ÃâµÇ´Â °æ¿ì¶ó¸é ºÎ°¡ÀûÀÎ function entry/exit ¶§¹®¿¡ ¼º´É¿¡µµ ÁÁÁö¾Ê½À´Ï´Ù. ÀÌ·± °æ¿ì¿¡ inline assembly¸¦ ¾²°ÔµË´Ï´Ù. ¿ì¼± ¾î¶² °ÍÀÎÁö °¨À» Àâ±â À§ÇØ ¿¹Á¦¸¦ º¸°Ú½À´Ï´Ù. void die(void) { dump_processor(); printk("halting the machine\n"); __asm__ __volatile__("cli; hlt;"); } dump_processor, printkÀÇ È£Ãâ±îÁö´Â ÀϹÝÀûÀÎ CÇÔ¼öÀÇ ¸ð½ÀÀ» °¡Áö°í ÀÖ½À´Ï´Ù. __asm__À¸·Î ½ÃÀÛÇÏ´Â ºÎºÐÀÌ inline assemblyÀε¥ °ýÈ£¾ÈÀÇ ¹®ÀÚ¿­ "cli; hlt;"°¡ compileÀ» µÈ assembly ÄÚµåÀÇ ÇØ´çÇÏ´Â ÀÚ¸®¿¡ ±×´ë·Î Ãâ·ÂÀÌ µÇ¾î °°ÀÌ ¾î¼ÀºíµË´Ï´Ù. cli´Â clear interruptÀÌ°í hlt ´Â haltÀÔ´Ï´Ù. Áï cli; hlt;ÀÇ µÎ ÀνºÆ®·°¼ÇÀ» ¼öÇàÇÏ°Ô µÇ¸é ÇÁ·Î¼¼¼­´Â ±Í¸¦ ¸·°í Àáµé°Ô µË´Ï´Ù. Áï À§ÀÇ ÇÔ¼ö´Â ÇÁ·Î¼¼¼­ÀÇ »óŸ¦ dumpÇÏ°í ¸ØÃâ °ÍÀ̶ó´Â °ÍÀ» Ãâ·ÂÇÑ ´ÙÀ½¿¡ ±â°è¸¦ ¸ØÃä´Ï´Ù. À§ÀÇ °æ¿ìó·³ ¸î°³ÀÇ Æ¯¼öÇÑ instructionÀ» ½á¾ßÇÏ´Â °æ¿ì¿¡ ¸Å¿ì °£ÆíÇÏ°Ô ¾µ ¼ö ÀÖ½À´Ï´Ù. ÀÌ¿Ü¿¡µµ inline assembly¸¦ ½Ã¿ëÇϸé CÀÇ º¯¼ö¸¦ assembly¿¡¼­ ¾µ ¼ö ÀÖ°í ·¹Áö½ºÅ͵éÀ» ¾î¶»°Ô ´Ù·ê Áö¸¦ ÁöÁ¤ÇÒ ¼öµµ ÀÖ½À´Ï´Ù. Â÷Â÷ »ìÆ캸µµ·Ï ÇÏ°Ú½À´Ï´Ù.
Inline assembly basics ¿ì¼± µÑ·¯º¸±â¿¡¼­ ¿¹Á¦¸¦ ÅëÇØ ¾î¶»°Ô »ý°å°í °¢°¢ÀÇ ºÎºÐÀÇ Àǹ̴ ¹«¾ùÀ̸ç gcc°¡ ÄÄÆÄÀÏÇßÀ» ¶§ ¾î¶² °á°ú¸¦ ³»¾î³õ´Â Áö¸¦ °£´ÜÈ÷ »ìÆ캻 ÈÄ °¢°¢ÀÇ ºÎºÐ¿¡ ´ëÇØ ÀÚ¼¼È÷ ¼³¸íÇÏ°Ú½À´Ï´Ù.
µÑ·¯º¸±â inline assembly¿¡¼­ Á¤ÇØÁÖ¾î¾ß ÇÏ´Â °ÍµéÀº ´ÙÀ½°ú °°½À´Ï´Ù. assembly ÄÚµå output º¯¼öµé input º¯¼öµé output¿Ü¿¡ °ªÀÌ ¹Ù²î´Â ·¹Áö½ºÅ͵é __asm__ __volatile__ (asms : output : input : clobber); asms ½Öµû¿ÈÇ¥·Î µÑ·¯½ÎÀÎ assembly ¹®ÀÚ¿­. ¹®ÀÚ¿­¾È¿¡¼­ %n ÇüÅ·Πinput, output ÀÎÀÚµéÀ» »ç¿ëÇÒ ¼ö ÀÖÀ¸¸ç ÀÎÀÚµéÀÌ Ä¡È¯µÈ ÈÄ ±×´ë·Î ÄÄÆÄÀÏ µÈ assembly¿¡ ³ªÅ¸³³´Ï´Ù. output ½°Ç¥·Î ±¸ºÐµÈ "constraint" (variable)µéÀÇ ¸®½ºÆ®ÀÌ¸ç °¢°¢ÀÌ ÀÌ inline assembly¿¡¼­ ¾²ÀÌ´Â output ÀÎÀÚ¸¦ ³ªÅ¸³À´Ï´Ù. input output°ú °°Àº ÇüÅÂÀ̸ç input ÀÎÀÚµéÀ» ³ªÅ¸³À´Ï´Ù. clobber ½°Ç¥·Î ±¸ºÐµÇ´Â ½Öµû¿ÈÇ¥·Î µÑ·¯½ÎÀÎ ·¹Áö½ºÅÍ À̸§µéÀÇ ¸®½ºÆ®À̸ç input, output¿¡ ³ª¿ÀÁø ¾Ê¾ÒÁö¸¸ ÇØ´ç assembly¸¦ ¼öÇàÇÑ °á°ú·Î °ªÀÌ ¹Ù²î´Â ·¹Áö½ºÅ͵éÀ» ³ªÅ¸³À´Ï´Ù. ouput, input, clobber´Â ºñ¾îÀÖ´Ù¸é µÚ¿¡¼­ ºÎÅÍ »ý·«µÉ ¼ö ÀÖ½À´Ï´Ù. ÇÏÁö¸¸ ¾Õ¿¡ ¿À´Â ÆĶó¹ÌÅÍ°¡ ºñ¾îÀÖÀ» ¶§´Â :·Î Ç¥½Ã¸¦ ÇØÁÖ¾î¾ß ÇÕ´Ï´Ù. Áï, __asm__ __volatile__(asms : output : input); /* clobber ¾øÀ» ¶§ */ __asm__ __volatile__(asms : : input); /* output, clobber ¾øÀ» ¶§ */ ÀÇ ÇüÅ·Π»ý·« °¡´ÉÇÕ´Ï´Ù. __asm__ Å°¿öµå´Â asmÀ¸·Îµµ ¾µ ¼ö ÀÖÁö¸¸ ansi¿É¼ÇÀ¸·Î ÄÄÆÄÀÏÇÏ°Ô µÇ¸é asmÀº Á¤ÀǵǾîÀÖÁö ¾Ê±â ¶§¹®¿¡ __asm__À¸·Î ¾²´Â °ÍÀÌ ÁÁ½À´Ï´Ù. __volatile__Àº ÇØ´çÇÏ´Â inline assembly¸¦ optimizationÀ¸·Î ¾ø¾Ö°Å³ª À§Ä¡¸¦ ¹Ù²ÙÁö¸»¶ó´Â ¶æÀÔ´Ï´Ù. GCC manual¿¡ µû¸£¸é side effect°¡ ¾ø´Ù°í ¿©°ÜÁö´Â °æ¿ì assembly¸¦ ¾ø¾Ö°Å³ª loopÀÇ ¹ÛÀ¸·Î »©´Â optimizationÀ» ÇÒ ¼ö ÀÖ´Ù°í ÇÕ´Ï´Ù. ¿¹¸¦ µé¾î outputÀÌ ÀÖÁö¸¸ ½ÇÁ¦·Î outputÀ¸·Î ¾²ÀÎ º¯¼ö°¡ ±× ÀÌÈÄ·Î ÇÑ ¹øµµ ¾²ÀÌÁö ¾Ê¾Ò´Ù¸é ±× inline assembly´Â ÇÁ·Î±×·¥ÀÇ ¼öÇà¿¡ ¾Æ¹«·± ¿µÇâÀ» ³¢Ä¡Áö ¾Ê´Â´Ù°í »ý°¢ÇÏ°í ¾ø¾Ö¹ö¸®´Â °ÍÀÔ´Ï´Ù. ¹°·Ð Á¶°ÇÀ» Á¤È®ÇÏ°Ô Á¤ÇØÁÖ¸é ±»ÀÌ __volaitile__À» ºÙÀÌÁö ¾Ê´õ¶óµµ Á¦´ë·Î ÀÛµ¿ÇÏ°ÚÁö¸¸ °¡²û¾¿ ¾û¶×ÇÏ°Ô µÇ¹ö¸®´Â °æ¿ìµµ Àֱ⶧¹®¿¡ Àß »ý°¢Çؼ­ inline assembly¸¦ ¾²°í __volatile__À» ºÙ¿©ÁÖ´Â °ÍÀÌ ÁÁ½À´Ï´Ù. ½ÇÁ¦·Î input, outputÀÌ ¾²ÀÎ ¿¹¸¦ º¸°Ú½À´Ï´Ù. int test_and_set_bit(int nr, volatile unsigned * addr) { int oldbit; __asm__ __volatile__( "lock; btsl %2,%1\n\tsbbl %0,%0" :"=r" (oldbit),"=m" (*addr) :"r" (nr)); return oldbit; } asms lock; btsl %2, %1 sbbl %0, %0 output "=r" (oldbit), "=m" (*addr) input "r" (nr) asms¿¡¼­ \n\t ´ë½Å ;À» Àû¾îµµ µÇÁö¸¸ gcc¿¡ -S¿É¼ÇÀ» ÁÖ¾î assembly outputÀ» º¼ ¶§¿¡ ³ª¸ÓÁö ºÎºÐ°ú ÁÙÀ» ¸ÂÃß·Á¸é °¢ ÀνºÆ®·Â¼Ç »çÀ̸¦ \n\t·Î ±¸ºÐÇØÁÖ´Â °ÍÀÌ ÁÁ½À´Ï´Ù. %0 %1 %2 °¢°¢Àº ÀÎÀÚµéÀ» ³ªÅ¸³»´Âµ¥ output, input¿¡ ÀÖ´Â ¼ø¼­´ë·Î ¹øÈ£°¡ ÁÖ¾îÁý´Ï´Ù. Áï, %0Àº oldbit, %1Àº *addr, %2´Â rÀÌ µË´Ï´Ù. À§ÀÇ assembly´Â lock; btsl nr, *addr sbbl oldbit ¿Í °°Àº ÀǹÌÀÔ´Ï´Ù. ÇÏÁö¸¸ instruction¿¡ µû¶ó¼­ ÀÎÀÚ·Î ¹«¾ùÀ» ¾µ ¼ö ÀÖ´Â Áö Á¦¾àÀÌ ÀÖ½À´Ï´Ù. ¿¹¸¦ µé¾î btslÀÇ °æ¿ì¿¡´Â ù¹ø° ÀÎÀÚ´Â ¹ü¿ë ·¹Áö½ºÅ͸¸À», µÎ¹ø° ÀÎÀڷδ ¹ü¿ë ·¹Áö½ºÅͳª memory»óÀÇ º¯¼ö°¡ µÉ ¼ö ÀÖ½À´Ï´Ù. µû¶ó¼­ gcc¿¡°Ô ¾î¶² ÀÎÀÚµéÀ» inline assembly¿¡¼­ ¾²°Ú´Ù´Â °Í »Ó¸¸¾Æ´Ï¶ó ±× ÀÎÀÚµéÀÌ ¾îµð¿¡ ÀÖ¾î¾ß ÇÏ´ÂÁöµµ Á¤ÇØÁÖ¾î¾ß ÇÕ´Ï´Ù. ÀÌ°ÍÀ» constraint¿¡¼­ Á¤ÇØÁÝ´Ï´Ù. outputÀ» º¸¸é oldbit, *addr·Î ÀÎÀÚ¸¦ Á¤ÇØÁÖ¾ú°í oldbit¿¡ ´ëÇؼ­´Â "=r", *addr¿¡ ´ëÇؼ­´Â "=m"À» constraint·Î ÁÖ¾ú½À´Ï´Ù. rÀº ¹ü¿ë ·¹Áö½ºÅ͸¦ ¶æÇÏ°í mÀº memory operand¸¦ ¶æÇÕ´Ï´Ù. Áï, oldbit°ú *addrÀº outputÀ¸·Î ¾²À̸ç oldbitÀº ¹ü¿ë ·¹Áö½ºÅÍ¿©¾ßÇÏ°í *addrÀº memory operandÀ̾î¾ß ÇÑ´Ù´Â ¶æÀÔ´Ï´Ù. Output ÀÎÀÚÀÇ °æ¿ì¿£ Ç×»ó =¸¦ constraint¿¡ Æ÷ÇÔ½ÃÄѾßÇϴµ¥ ÀÌ°ÍÀº ÀÌ ÀÎÀÚÀÇ °ªÀº inline assemblyÀÇ °á°ú·Î ¹Ù²ð ¼ö ÀÖ´Ù¶ó´Â °ÍÀ» ¶æÇÕ´Ï´Ù. Inputµµ °°½À´Ï´Ù. nrÀº inputÀ¸·Î ¾²ÀÌ¸ç ¹ü¿ë ·¹Áö½ºÅÍÀ̾î¾ß ÇÑ´Ù´Â constraint¸¦ °¡Áö°í ÀÖ½À´Ï´Ù. ÇÏÁö¸¸ inputÀÇ °æ¿ì¿¡´Â =ÀÌ ¾ø½À´Ï´Ù. ¿©·¯°³ÀÇ constraint¸¦ °°ÀÌ ¾µ ¼öµµ ÀÖ½À´Ï´Ù. Áï, "ir" (nr) ó·³ ¾µ ¼ö ÀÖ½À´Ï´Ù. ÀÌ·¸°Ô ¾²¸é ÁÖ¾îÁø ¿©·¯°³ÀÇ constraintÁß Çϳª¸¦ ¸¸Á·ÇÏ¸é µÈ´Ù´Â ¶æÀ¸·Î "ir"Àº immediate operand³ª ¹ü¿ë ·¹Áö½ºÅÍÁß Çϳª¸é µÈ´Ù´Â ¶æÀÔ´Ï´Ù. À§ÀÇ ÇÔ¼ö´Â À̸§Ã³·³ addr·Î ÁÖ¾îÁø wordÀÇ nr¹ø° bitÀ» atomic test and setÇÕ´Ï´Ù. º¸Åë spin lockÀ̳ª semaphoreµîÀÇ synchornization constructµéÀ» ¸¸µé ¶§ ¾²ÀÔ´Ï´Ù. ±â´ÉÀ» »ý°¢Çغ¸¸é addrÀÇ constraint°¡ ¿Ö ¹ü¿ë ·¹Áö½ºÅͰųª memory operand°¡ ¾Æ´Ï¶ó memory operand·Î¸¸ °íÁ¤À̵Ǿî ÀÖ´Â Áö ¾Ë ¼ö ÀÖ½À´Ï´Ù. ¸¸¾à ¹ü¿ë ·¹Áö½ºÅÍ·Î ÇÒ´çµÇ¾î ¹ö¸®¸é *addr¿¡ ÀÖ´Â °ªÀ» ÇÒ´çµÈ ·¹Áö½ºÅÍ·Î loadÇÑ ÈÄ¿¡ btsl°ú sbblÀÌ ¼öÇàµÇ°í ±× °á°ú°ªÀÌ ´Ù½Ã *addr·Î storeµÇ¹Ç·Î atomicÇÏÁö ¾Ê°Ô µÇ¹ö¸³´Ï´Ù. Gcc´Â constraint¿¡ µû¶ó¼­ °¢°¢ÀÇ ÀÎÀÚµéÀ» ÇÒ´çÇÑ ÈÄ¿¡ ÇÊ¿äÇϸé input º¯¼öµéÀ» ÇÒ´çµÈ °÷¿¡ loadÇÏ´Â code¸¦ »ý¼ºÇÏ°í inline assembly¿¡ %n ÇüÅÂÀÇ º¯¼öµéÀ» ÇÒ´çµÈ ½ÇÁ¦ º¯¼ö·Î ġȯÇؼ­ code¸¦ ³»¾î³õ½À´Ï´Ù. ÄÄÆÄÀÏ·¯´Â inline assembly°¡ ½ÇÇàµÈ ÈÄ¿¡ ±× °á°ú°ªµéÀÌ ¾îµð¿¡ ÀÖ´Â Áö ¾Ë°í ÀÖÀ¸¹Ç·Î ±× ÀÌÈÄÀÇ ÄÄÆÄÀÏÀ» °è¼Ó ÁøÇàÇÒ ¼ö ÀÖ½À´Ï´Ù. ±×·³ À§ÀÇ ÇÔ¼ö°¡ ½ÇÁ¦·Î ÄÄÆÄÀÏ µÇ¾úÀ» ¶§ ¾î¶² °á°ú°¡ ³ª¿À´Â Áö º¸°Ú½À´Ï´Ù. .globl test_and_set_bit .type test_and_set_bit,@function test_and_set_bit: movl 4(%esp),%eax movl 8(%esp),%edx #APP lock; btsl %eax,(%edx) sbbl %eax,%eax #NO_APP ret È£ÃâÇÏ´Â ºÎºÐ¿¡¼­ stack¿¡ addr, nr, return address¸¦ pushÇÏ°í test_and_set_bitÀ¸·Î controlÀÌ ³Ñ¾î¿À¸é, nrÀ» eax¿¡ addrÀ» edx¿¡ loadÇÑ ÈÄ #APP, #NO_APP»çÀÌÀÇ inline asembly°¡ ½ÇÇàµË´Ï´Ù. btslÀÇ Ã¹¹ø° ÀÎÀÚ %2´Â nrÀÌ loadµÈ %eax·Î, µÎ¹ø° ÀÎÀÚ %1Àº addrÀÌ loadµÈ %edxÀÇ indirect addressingÀÎ (%edx)·Î, sbblÀÇ ÀÎÀÚÀÎ %0´Â %eax·Î ġȯµÈ °ÍÀ» ¾Ë ¼ö ÀÖ½À´Ï´Ù. Return °ªÀº Å©±â°¡ ¸Â´Â °æ¿ì %eax¸¦ ÅëÇؼ­ °¡°í inline assembly ½ÇÇà ÈÄ returnÇÒ °ªÀÌ ÀÌ¹Ì %eax¿¡ ÀÖÀ¸¹Ç·Î ±×³É ret¸¦ ½ÇÇàÇÕ´Ï´Ù. %0¿Í %2°¡ °°Àº ·¹Áö½ºÅÍ·Î ÇÒ´çµÇ¾ú´Âµ¥, gcc´Â ±âº»ÀûÀ¸·Î ¸ðµç inputº¯¼öµéÀº output º¯¼ö°¡ »ç¿ëµÇ±â Àü¿¡ ¸ðµÎ »ç¿ëµÈ´Ù°í »ý°¢Çؼ­ °ãÄ¡°Ô ÇÒ´çÇÒ ¼öµµ ÀÖ½À´Ï´Ù. À§ÀÇ °æ¿ì¿¡¼± %2°¡ %0°¡ »ç¿ëµÇ±â Àü¿¡ »ç¿ëµÇ¾úÀ¸¹Ç·Î ¹®Á¦°¡ ¾øÁö¸¸ ±×·¸Áö ¾ÊÀº °æ¿ì¿£ output º¯¼öÀÇ constraint¿¡ '&'¸¦ ´õÇØ early clobber¸¦ Á¤ÇØÁÖ¾î¾ß ÇÕ´Ï´Ù. Early clobber¿¡ ´ëÇؼ± output º¯¼ö Ç׸ñ¿¡¼­ ¼³¸íÇÏ°Ú½À´Ï´Ù. ÀÌÁ¦ Àüü¸¦ ÇÑ ¹ø º¸¾Ò½À´Ï´Ù. ±×´ÙÁö º¹ÀâÇÏÁö ¾ÊÁö¿ä? ÀÌÁ¦ °¢ ºÎºÐ¿¡´ëÇØ ÀÚ¼¼È÷ ¾Ë¾Æº¸µµ·Ï ÇÏ°Ú½À´Ï´Ù.
Assembly ÀÌ ¼½¼Ç¿¡¼­´Â gcc inline assembly¿¡¼­ ½ÇÁ¦ assembly¸¦ Àû´Â ºÎºÐ (¾ÕÀ¸·Î´Â ÀÌ ºÎºÐÀ» asms¶ó°í ºÎ¸£°Ú½À´Ï´Ù)¿¡ ´ëÇØ ¼³¸íÇÕ´Ï´Ù. asmsÀÇ ³»¿ëÀº ±×´ë·Î ÄÄÆÄÀÏ µÈ assembly¿Í ÇÔ²² gasmÀ¸·Î ³Ñ¾î°¡¹Ç·Î gasmÀÇ ¹®¹ýÀ» µû¶ó¾ß ÇÕ´Ï´Ù. GasmÀº target ÀÎÀÚ°¡ µÚ¿¡¿À´Â AT&T ¹®¹ýÀ» µû¸£¸ç instruction »çÀÌÀÇ ±¸ºÐÀº ¼¼¹ÌÄÝ·ÐÀ̳ª °³Ç๮ÀÚ·Î ÇÏ°í ·¹Áö½ºÅ͵éÀº %registerÀÇ ÇüÅ·ΠǥÇöÇÕ´Ï´Ù. ix86 °è¿­ÀÇ ´ëºÎºÐÀÇ ¾î¼Àºí·¯¿Í intel manualÀº target ÀÎÀÚ°¡ ¾Õ¿¡¿À´Â intel ¹®¹ýÀ» µû¸£°í ÀÖÀ¸¹Ç·Î manualÀ» º¸°Å³ª ´Ù¸¥ ¾î¼Àºí·¯ÀÇ Äڵ带 º¼ ¶§ ÁÖÀÇÇϽñ⠹ٶø´Ï´Ù. ´õ ÀÚ¼¼ÇÑ ³»¿ëÀº gasm ¸Þ´º¾ó°ú intel processor manualÀ» ÂüÁ¶Çϼ¼¿ä.
µé¿©¾²±â & Ä¿¸àÆ® ´Þ±â Gcc°¡ »ý¼ºÇÏ´Â assembly ÄÚµå´Â ½Éº¼ Á¤ÀǵîÀ» Á¦¿ÜÇÏ°í´Â ¸ðµÎ ÅÇ Çϳª¸¸Å­ µé¿©¾²±â°¡ µÇ¾îÀÖ½À´Ï´Ù. Inline assembly´Â #APP¿Í #NO APP»çÀÌ¿¡ µé¾î°¡´Âµ¥ ÅÇ Çϳª¸¸Å­ µé¿©¾²±â°¡ µÈ »óÅ¿¡¼­ ¹®ÀÚ¿­ÀÌ ±×´ë·Î µé¾î°©´Ï´Ù. µû¶ó¼­ Assembly outputÀ» Àб⠽±°Ô Çϱâ À§ÇØl¼± °¢ instructionµé »çÀ̸¦ \n\t·Î ±¸ºÐÇØÁÖ¸é µË´Ï´Ù. __asm__ __volatile__("line1\n\tline2\line3"); À» ÄÄÆÄÀÏÇϸé #APP line1 line2 line3 #NO_APP °¡ µË´Ï´Ù. ±×·±µ¥ ³»¿ëÀÌ ¸¹¾ÆÁö¸é À§Ã³·³ ÇÑ ÁÙ·Î Àû±â°¡ Èûµé¾îÁý´Ï´Ù. ±×·± °æ¿ì¿£ ¾Æ·¡Ã³·³ ÇÏ¸é µË´Ï´Ù. __asm__ __volatile__( "pushl %%ebp # comment \n\t" "movl %%esp, %%eax \n\t" "cli" \n\t" "incl %0 \n\t" "movl %8, %%esp \n\t" "sti" \n\t" "pushl %%eax \n\t" "call *%7 \n\t" "cli \n\t" "decl %0 \n\t" "popl %%esp # comment 2 \n\t" "sti \n\t" "popl %%ebp " : "=m" (processor0->intr_lv), "=&a" (a), "=b" (b), "=c" (c), "=d" (d), "=D" (D), "=S" (S) : "m" (jmpaddr), "g" (processor0->bh_stack_top)); ÄÄÆÄÀÏ Çϸé, #APP pushl %ebp # comment movl %esp, %eax cli incl processor0+20 movl processor0+76, %esp sti pushl %eax call *-40(%ebp) cli decl processor0+20 popl %esp # comment 2 sti popl %ebp #NO_APP Gasm¿¡¼­ Ä¿¸àÆ®´Â #ºÎÅÍ ±× ÁÙÀÇ ³¡±îÁöÀ̸ç inline assembly¿¡¼­µµ °°Àº ¹æ¹ýÀ¸·Î ¾µ ¼ö ÀÖ½À´Ï´Ù.
Register Á÷Á¢ ÁöÁ¤Çϱâ À§ÀÇ ¿¹¿¡¼­ %%eax, %%esp°°Àº °ÍµéÀ» º¼ ¼ö Àִµ¥ %%´Â ½ÇÁ¦ output¿¡¼­ % Çϳª¸¦ Ãâ·ÂÇÕ´Ï´Ù. ƯÁ¤ ·¹Áö½ºÅ͸¦ ½á¾ßÇÒ ¶§´Â %nÀ¸·Î Á¤ÇØÁ൵ µÇÁö¸¸ input, output ÁöÁ¤¿¡¼­ ¾²°í ½ÍÀº ·¹Áö½ºÅ͸¦ ÁöÁ¤ÇÏ°í ¾îÂ÷ÇÇ ±× ·¹Áö½ºÅÍ°¡ ÇÒ´çµÉ °ÍÀ» ¾Ë°í ÀÖÀ¸¹Ç·Î %%register¸¦ ¾²´Â °ÍÀÌ ´õ ÀÐ°í ¾²±â ÆíÇÕ´Ï´Ù. ÇÑ °¡Áö ÁÖÀÇÇÒ Á¡Àº ¸¸¾à input, outputÀÌ Çϳªµµ ¾ø´Â °æ¿ì¿¡´Â asms¿¡ ´ëÇÑ ÀÎÀÚġȯÀÌ ÀüÇô ÀϾÁö ¾Ê°í %%µµ %·Î ¹Ù²îÁö ¾Ê½À´Ï´Ù. Áï, input, outputÀÌ ¸ðµÎ ¾øÀ» ¶§´Â %%register´ë½Å %register¶ó°í ÇؾßÇÕ´Ï´Ù.
Inline assembly¾È¿¡¼­ ÇÔ¼ö Á¤ÀÇÇϱâ ÇÔ¼ö¸¦ assembly·Î Á¤ÀÇÇؾßÇÏ´Â °æ¿ì´Â ÁÖ·Î ÇÔ¼öÀÇ entry³ª exitÀÌ CÀÇ convention°ú ´Þ¶ó¼­ CÇÔ¼ö ¾È¿¡¼­ inline assembly·Î ¸¸µé ¼ö ¾ø´Â °æ¿ìÀÔ´Ï´Ù. ¹°·Ð µû·Î ¾î¼Àºí¸® È­ÀÏÀ» ¸¸µé¾îµµ µÇÁö¸¸ ÀÌ·± ÇÔ¼ö°¡ ¸î °³ µÇÁö ¾ÊÀ» ¶§´Â ¹ø°Å·Ó±â ¶§¹®¿¡ inline assembly·Î ¸¸µå´Â °ÍÀÌ ´õ ÆíÇÕ´Ï´Ù. ¶Ç, assembly·Î ¸¸µç ÇÔ¼ö¿¡¼­ C ÇÁ·Î±×·¥¿¡¼­ ¾²´ø Àü¿ªº¯¼ö, ¸ÅÅ©·ÎµîÀ» ¾²°ÔµÇ´Â °æ¿ì°¡ Àִµ¥, ÀϹÝÀûÀÎ °æ¿ì assembly ¼Ò½º¸¦ C preprocessor·Î ó¸®ÇÏ°í ¸µÅ©ÇÏ¸é µÇÁö¸¸ Àü¿ªÀ¸·Î ¼±¾ðµÈ structure¸¦ »ç¿ëÇÏ·Á¸é ¹®Á¦°¡ µË´Ï´Ù. ½ºÅ©¸³µåµîÀ» »ç¿ëÇؼ­ memberµéÀÇ offsetÀ» Æ÷ÇÔÇÑ Çì´õÈ­ÀÏÀ» ¸¸µç ÈÄ C preprocessor¸¦ »ç¿ëÇÏ¸é °¡´ÉÇϱä ÇÏÁö¸¸ (½ÇÁ¦·Î freebsd Ä¿³Î¿¡¼± ÀÌ ¹æ¹ýÀ» »ç¿ëÇÕ´Ï´Ù) »ó´çÈ÷ ±ÍÂúÀº ÀÏÀÌ µÇ¹ö¸³´Ï´Ù. ÀÌ·± °æ¿ì¿¡µµ inline assembly·Î ÇÔ¼ö¸¦ Á¤ÀÇÇØ ÁÖ´Â °ÍÀÌ ÈξÀ °£ÆíÇÕ´Ï´Ù. AsmsÀÇ ³»¿ëÀÌ output¿¡ ±×´ë·Î Ãâ·ÂµÇ±â ¶§¹®¿¡ ½Éº¼À» Á¤ÀÇÇÏ´Â directiveµµ »ç¿ëÇÒ ¼ö ÀÖ½À´Ï´Ù. ¿ì¼± ¿¹¸¦ º¸°Ú½À´Ï´Ù. struct { int a; int b; } mine = { 0, 0 }; int iasm_test_func(int arg); static int iasm_test_func2(void); static void __iasm_function_dummy(void) { __asm__ __volatile__( ".globl iasm_test_func \n\t" "iasm_test_func: \n\t" "pushl 4(%%esp) \n\t" "pushl %2 \n\t" "pushl %1 \n\t" "pushl %0 \n\t" "call printf \n\t" "addl $16, %%esp \n\t" "ret " : : "i" ("hello world.. mine.a=%d mine.b=%d arg=%d\n"), "g" (mine.a), "g" (mine.b)); __asm__ __volatile__( "iasm_test_func2: \n\t" "pushl $32 \n\t" "call iasm_test_func \n\t" "addl $4, %esp "); } int main(void) { mine.a = 123; mine.b = 321; iasm_test_func(16); return iasm_test_func2(); } ¿ì¼± Á¤ÀÇÇÒ µÎ ÇÔ¼öÀÇ prototypeÀ» º¼ ¼ö ÀÖ½À´Ï´Ù. iasm_test_func2´Â staticÀÎ °É ÁÖÀÇÇؼ­ º¸½Ã±â ¹Ù¶ø´Ï´Ù. Inline assembly´Â ÇÔ¼ö¹Û¿¡¼­´Â ¾²ÀÏ ¼ö ¾øÀ¸¹Ç·Î __iasm_function_dummy¶ó´Â ÇÔ¼ö¸¦ ¸¸µé°í ±× ¾ÈÀÇ µÎ inline assembly¿¡¼­ °¢°¢ ÇÔ¼ö¸¦ Á¤ÀÇÇß½À´Ï´Ù. ù¹ø° ÇÔ¼ö´Â iasm_test_func·Î ½Éº¼ Á¤ÀÇ ¹Ù·ÎÀ§ÀÇ .globl directive·Î ¸µÅ©½Ã ¿ÜºÎ¿¡ º¸ÀÌ´Â ½Éº¼ÀÓÀ» ¾Ë·ÁÁÖ¾ú°í µÎ¹ø°ÀÇ iasm_test_func2ÇÔ¼ö´Â .globlÀÌ ¾øÀ¸¹Ç·Î ¸µÅ©½Ã ¿ÜºÎ¿¡¼­ º¸ÀÌÁö ¾Ê´Â static ÇÔ¼ö°¡ µË´Ï´Ù. Gcc´Â ÄÄÆÄÀÏ ÇÒ ¶§ iasm_test_func2°¡ inline assembly¾È¿¡ Á¤ÀǵǾî ÀÖ´Â °É ¾ËÁö ¸øÇϹǷΠstaticÇÔ¼ö°¡ Á¤ÀǵÇÁö ¾Ê¾Ò´Ù°í °æ°í¸¦ ÇÏÁö¸¸ ¹«½ÃÇÏ¸é µË´Ï´Ù. iasm_test_func´Â Á¤¼ö ÀÎÀÚ¸¦ Çϳª ¹Þ°í, Àü¿ª ±¸Á¶Ã¼ÀÎ mineÀÇ ³»¿ë°ú ¹ÞÀº ÀÎÀÚÀÇ °ªÀ» printf¸¦ »ç¿ëÇØ Ãâ·ÂÇÏ´Â ÇÔ¼ö ÀÔ´Ï´Ù. Inline assembly¸¦ º¸¸é inputÀ¸·Î format ¹®ÀÚ¿­, mine.a, mine.b°¡ »ç¿ëµÇ´Âµ¥ "i"´Â immediate integer operand·Î format ¹®ÀÚ¿­ÀÇ ½ÃÀÛ ÁÖ¼Ò°¡ ±×´ë·Î operand°¡ µË´Ï´Ù. "g"´Â immediate, ¹ü¿ë ·¹Áö½ºÅÍ ¶Ç´Â memory operand¸¦ ¶æÇÏ´Â °ÍÀ¸·Î compiler°¡ ÀûÀýÈ÷ ¼±ÅÃÇÕ´Ï´Ù. iasm_test_func2´Â iasm_test_func(32)¸¦ È£ÃâÇÏ´Â ÇÔ¼öÀÔ´Ï´Ù. À§ÀÇ ÇÁ·Î±×·¥À» ÄÄÆÄÀÏÇÏ¸é ¾Æ·¡¿Í °°Àº assembly°¡ µË´Ï´Ù. (gcc -fomit-frame-pointer -mpreferred-stack-boundary=2 -O2 -S iasm_function.c) .file "iasm_function.c" .version "01.01" gcc2_compiled.: .globl mine .data .align 4 .type mine,@object .size mine,8 mine: .long 0 .long 0 .section .rodata .align 32 .LC0: .string "hello world.. mine.a=%d mine.b=%d arg=%d\n" .text .align 4 .type __iasm_function_dummy,@function __iasm_function_dummy: #APP .globl iasm_test_func iasm_test_func: pushl 4(%esp) pushl mine+4 pushl mine pushl $.LC0 call printf addl $16, %esp ret iasm_test_func2: pushl $32 call iasm_test_func addl $4, %esp #NO_APP ret .Lfe1: .size __iasm_function_dummy,.Lfe1-__iasm_function_dummy .align 4 .globl main .type main,@function main: movl $123,mine movl $321,mine+4 pushl $16 call iasm_test_func call iasm_test_func2 addl $4,%esp ret .Lfe2: .size main,.Lfe2-main .ident "GCC: (GNU) 2.95.4 20010902 (Debian prerelease)" __iasm_function_dummy¾È¿¡ µÎ °³ÀÇ inline assembly°¡ #APP, #NOAPP ¾È¿¡¼­ iasm_test_func, iasm_test_func2¸¦ Á¤ÀÇÇÏ°í ÀÖ°í, iasm_test_funcÀÇ %1, %2´Â direct addressingÀ¸·Î ó¸®µÈ °ÍÀ» º¼ ¼ö ÀÖ½À´Ï´Ù.
Output/Input List Output°ú inputÀº "constraint" (variable)µéÀÇ ½°Ç¥·Î ±¸ºÐµÈ ¸®½ºÆ®·Î ±¸¼ºµË´Ï´Ù. Constraint´Â ¾Æ·¡ÀÇ ¹®ÀÚµé°ú ¸î°¡Áö modifierµéÀÇ Á¶ÇÕÀ¸·Î Çã¿ëµÇ´Â operandÀÇ Á¾·ù¿Í ±× operand°¡ inline assembly¿¡¼­ ¾î¶»°Ô »ç¿ëµÇ´ÂÁö¸¦ ³ªÅ¸³À´Ï´Ù. ¾Æ·¡ÀÇ ¸®½ºÆ®´Â ¿ÏÀüÇÏÁö ¾Ê½À´Ï´Ù. Gcc ¸Þ´º¾óÀ» ÂüÁ¶Çϼ¼¿ä.
Constraints
Basic constraints 'm' Architecture°¡ ÀϹÝÀûÀ¸·Î Áö¿øÇÏ´Â ¸ðµç addressing modeÁß Çϳª¸¦ »ç¿ëÇÏ´Â memory operand. 'r' ¹ü¿ë ·¹Áö½ºÅÍ operand. 'd', 'a', 'f', ... ·¹Áö½ºÅ͸¦ ÀûÁ¢ ÁöÁ¤ÇÏ´Â constraint. Architecture¸¶´Ù ´Ù¸¥ ¹®ÀÚµéÀ» Á¤ÀÇÇÕ´Ï´Ù. 'd', 'a', 'f'´Â 68000/68020¿¡¼­ ¾²´Â ¹®ÀÚµéÀÔ´Ï´Ù. 'i' Á¤¼ö immediate operand. AssembleÇÒ ¶§°¡ µÇ¾î¾ß ¾Ë ¼ö ÀÖ´Â symbol°ª(ÁÖ¼Ò)µéµµ ÇØ´çµË´Ï´Ù. 'n' °ªÀ» Á¤È®È÷ ¾Ë°í ÀÖ´Â Á¤¼ö. Symbol°ªµéÀº ÇØ´çµÇÁö ¾Ê½À´Ï´Ù. 'I', 'J', 'K', ... 'P' ¹Ì¸® Á¤ÇØÁø ¹üÀ§¾ÈÀÇ Á¤¼ö immediate operand. ¿¹¸¦ µé¾î 68000¿¡¼­ 'I'´Â 1¿¡¼­ 8»çÀÌÀÇ immediate operand¸¦ ¶æÇϸç shift operationÀÇ shift cound·Î ¾²ÀÔ´Ï´Ù. 'E' Compling machine°ú target machineÀÇ floating Ç¥Çö ¹æ½ÄÀÌ °°À» ¶§ immediate floating operand¸¦ Çã¿ëÇÕ´Ï´Ù. 'F' Immediate floating operand. 'G', 'H' Machine¿¡ µû¶ó Á¤ÀǵǴ ƯÁ¤ÇÑ ¹üÀ§³»ÀÇ immediate floating point operand. 'g' ¹ü¿ë ·¹Áö½ºÅÍ, memory, immediate operand Áß ¹«¾ùÀÌ¶óµµ µË´Ï´Ù. 'X' ¾î¶°ÇÑ operand¶óµµ Çã¿ëÇÕ´Ï´Ù. 'p' À¯È¿ÇÑ ÁÖ¼Ò°¡ Çã¿ëµË´Ï´Ù. Load address, push addressµîÀÇ instruction¿¡ ¾²ÀÔ´Ï´Ù. 'Q', 'R', 'S', ... 'U' Machine-dependent.
i386 specific 'q' a, b, c, or d register 'A' a, or d register (for 64-bit ints) 'f' Floating point register 't' First (top of stack) floating point register 'u' Second floating point register 'a' a register 'b' b register 'c' c register 'd' d register 'D' di register 'S' si register 'I' Constant in range 0 to 31 (for 32bit shifts) 'J' Constant in range 0 to 63 (for 64bit shifts) 'K' 0xff 'L' 0xffff 'M' 0, 1, 2, or 3 (shifts for lea instruction) 'N' Constant in range 0 to 255 (for out instruction) 'G' Standard 80387 floating point constant
Modifiers Constraint modifierµéÀº ±× º¯¼ö°¡ ¾î¶»°Ô »ç¿ëµÇ´Â Áö¸¦ compiler¿¡°Ô ¾Ë·ÁÁÝ´Ï´Ù. ¾Æ·¡ÀÇ ¸®½ºÆ®´Â ¿ÏÀüÇÏÁö ¾Ê½À´Ï´Ù. Gcc ¸Þ´º¾óÀ» ÂüÁ¶Çϼ¼¿ä. '=' º¯¼öÀÇ °ªÀÌ ¹Ù²ñÀ» ³ªÅ¸³À´Ï´Ù. Outputµé¿¡ ´ëÇؼ­´Â ÀÌ modifier°¡ ¹Ýµå½Ã ÁöÁ¤µÇ¾î ÀÖ¾î¾ß ÇÕ´Ï´Ù. '&' Early clobber. ´ÙÀ½ Àý¿¡¼­ ÀÚ¼¼È÷ ¼³¸íÇÏ°Ú½À´Ï´Ù.
Early clobber #include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { int a, sum; a = atoi(argv[1]); __asm__ __volatile__( "movl %1, %0 \n\t" "addl %2, %0 \n\t" "addl %3, %0 \n\t" "addl %4, %0 \n\t" "addl %5, %0 " : "=g" (sum) : "g" (a), "g" (a+1), "g" (a+2), "g" (a+3), "g" (a+4)); printf("a=%d, sum=%d\n", a, sum); return 0; } À§ÀÇ ÇÁ·Î±×·¥À» ÄÄÆÄÀÏÇϸé .file "early_clobber.c" .version "01.01" gcc2_compiled.: .section .rodata .LC0: .string "a=%d, sum=%d\n" .text .align 4 .globl main .type main,@function main: pushl %esi pushl %ebx movl 16(%esp),%eax pushl $0 pushl $10 pushl $0 pushl 4(%eax) call __strtol_internal movl %eax,%esi addl $16,%esp leal 1(%esi),%edx leal 2(%esi),%ebx leal 3(%esi),%ecx leal 4(%esi),%eax #APP movl %esi, %edx addl %edx, %edx addl %ebx, %edx addl %ecx, %edx addl %eax, %edx #NO_APP pushl %edx pushl %esi pushl $.LC0 call printf xorl %eax,%eax addl $12,%esp popl %ebx popl %esi ret .Lfe1: .size main,.Lfe1-main .ident "GCC: (GNU) 2.95.4 20010902 (Debian prerelease)" #APP¿Í #NOAPP »çÀÌÀÇ inline assembly¿¡¼­ %0 (sum)¿¡ %edx°¡ ÇÒ´çµÇ¾úÀ½À» ¾Ë ¼ö ÀÖ½À´Ï´Ù. ±×·±µ¥ #APP¾Æ·¡ µÎ¹ø°ÁÙÀÌ addl %edx, %edx·Î %2 (a+1)µµ %edx·Î ÇÒ´çµÇ¾ú½À´Ï´Ù. Gcc´Â Ç×»ó ¸ðµç input º¯¼öµéÀÌ ´Ù »ç¿ëµÈ ÈÄ¿¡ output º¯¼öµéÀÌ ¾²ÀÎ´Ù°í °¡Á¤Çؼ­ input º¯¼ö¿Í output º¯¼ö¸¦ °°Àº operand¿¡ ÇÒ´çÇϱ⵵ ÇÕ´Ï´Ù. Input, outputÀÌ ÇϳªÀÇ operand¿¡ ÇÒ´çµÇ°í À§ÀÇ ¿¹Ã³·³ inputº¸´Ù outputÀ¸·Î ¸ÕÀú¾²ÀÌ°Ô µÇ¸é Ʋ¸° °á°ú°¡ ³ª¿É´Ï´Ù. ÀÌ·± °æ¿ì¿¡´Â gcc¿¡°Ô ±× output º¯¼ö´Â inputÀÇ °ªµéÀÌ ¸ðµÎ »ç¿ëµÇ±â Àü¿¡ °ªÀÌ ¹Ù²ð ¼ö ÀÖ´Ù´Â °ÍÀ» ¾Ë·ÁÁÖ¾î¾ß ÇÕ´Ï´Ù. ÀÌ°ÍÀ» ¾Ë·ÁÁÖ±â À§ÇÑ modifier°¡ early clobber modifier '&' ÀÔ´Ï´Ù. À§ÀÇ ÇÁ·Î±×·¥¿¡¼­ output constraint "=g" (sum)À» "=&g" (sum)À¸·Î ¹Ù²Ù°í ´Ù½Ã ÄÄÆÄÀÏÇÏ¸é ´ÙÀ½°ú °°Àº °á°ú°¡ ³ª¿É´Ï´Ù. .file "early_clobber.c" .version "01.01" gcc2_compiled.: .section .rodata .LC0: .string "a=%d, sum=%d\n" .text .align 4 .globl main .type main,@function main: pushl %edi pushl %esi pushl %ebx movl 20(%esp),%eax pushl $0 pushl $10 pushl $0 pushl 4(%eax) call __strtol_internal movl %eax,%esi addl $16,%esp leal 1(%esi),%ebx leal 2(%esi),%ecx leal 3(%esi),%edx leal 4(%esi),%eax #APP movl %esi, %edi addl %ebx, %edi addl %ecx, %edi addl %edx, %edi addl %eax, %edi #NO_APP movl %edi,%eax pushl %eax pushl %esi pushl $.LC0 call printf xorl %eax,%eax addl $12,%esp popl %ebx popl %esi popl %edi ret .Lfe1: .size main,.Lfe1-main .ident "GCC: (GNU) 2.95.4 20010902 (Debian prerelease)" Output º¯¼ö´Â %edi·Î ÇÒ´çµÇ¾ú°í ¾î¶² inputµµ °ãÄ¡°Ô ÇÒ´çµÇÁö ¾Ê¾ÒÀ½À» ¾Ë ¼ö ÀÖ½À´Ï´Ù.
Clobber list InputÀ̳ª outputÀ¸·Î »ç¿ëµÇÁö ¾ÊÁö¸¸ ¾î¶² ·¹Áö½ºÅ͸¦ inline assembly¿¡¼­ Àӽ÷Π»ç¿ëÇÒ ¶§ clobber list¿¡ ±× ·¹Áö½ºÅ͸¦ Àû½À´Ï´Ù. Clobber list¿¡ ÀÖ´Â ·¹Áö½ºÅÍ´Â input, output¿¡ ÀÖ´Â ·¹Áö½ºÅÍ¿Í °ãÄ¥ ¼ö ¾ø½À´Ï´Ù. Áï, clobber list¿¡ ÁöÁ¤µÈ ·¹Áö½ºÅÍ´Â input, outputÀ» À§ÇÑ ·¹Áö½ºÅÍ ÇÒ´ç¿¡¼­ ºüÁö°Ô µË´Ï´Ù. ¸¸¾à ¾î¶² ·¹Áö½ºÅÍ°¡ inputÀ¸·Î ¾²ÀÌ°í ±× °ªÀÌ ¹Ù²îÁö¸¸ outputÀ¸·Î ¾²ÀÌÁø ¾Ê´Â´Ù¸é clobber list¿¡ ±× ·¹Áö½ºÅ͸¦ Á¤ÇØÁÙ ¼ö ¾ø½À´Ï´Ù. ÀÌ·± °æ¿ì¿£ dummy º¯¼ö¸¦ Çϳª ¼±¾ðÇÑ ÈÄ output ÀÎÀڷεµ ÁöÁ¤ÇØÁÖ¾î¾ß ÇÕ´Ï´Ù. #include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { int a, b, r; a = atoi(argv[1]); b = atoi(argv[2]); __asm__ __volatile__( "movl %1, %%eax \n\t" "addl %2, %%eax \n\t" "mull %%eax " : "=&a" (r) : "g" (a), "g" (b)); printf("a=%d, b=%d, r=%d\n", a, b, r); return 0; } µÎ Á¤¼ö¸¦ ÀÔ·Â¹Þ¾Æ ÇÕÀÇ Á¦°öÀ» ±¸ÇÏ´Â ÇÁ·Î±×·¥ÀÔ´Ï´Ù. À§ÀÇ ÇÁ·Î±×·¥À» ÄÄÆÄÀÏÇÏ¸é ´ÙÀ½°ú °°Àº °á°ú°¡ ³ª¿É´Ï´Ù. .file "clobber_list.c" .version "01.01" gcc2_compiled.: .section .rodata .LC0: .string "a=%d, b=%d, r=%d\n" .text .align 4 .globl main .type main,@function main: pushl %esi pushl %ebx movl 16(%esp),%ebx pushl $0 pushl $10 pushl $0 pushl 4(%ebx) call __strtol_internal movl %eax,%esi addl $16,%esp pushl $0 pushl $10 pushl $0 pushl 8(%ebx) call __strtol_internal movl %eax,%edx addl $16,%esp #APP movl %esi, %eax addl %edx, %eax mull %eax #NO_APP pushl %eax pushl %edx pushl %esi pushl $.LC0 call printf xorl %eax,%eax addl $16,%esp popl %ebx popl %esi ret .Lfe1: .size main,.Lfe1-main .ident "GCC: (GNU) 2.95.4 20010902 (Debian prerelease)" b°¡ %edx·Î ÇÒ´çµÇ¾úÀ½À» ¾Ë ¼ö ÀÖ½À´Ï´Ù. b´Â inputÀ̹ǷΠ°ªÀÌ º¯ÇÏÁö ¾ÊÀº °ÍÀ¸·Î »ý°¢ÇØ inline assemblyÈÄ¿¡ printf¸¦ ºÎ¸¦ ¶§µµ %edxÀÇ °ªÀ» ±×´ë·Î »ç¿ëÇÏ´Â °ÍÀ» º¼ ¼ö ÀÖ½À´Ï´Ù. À§ÀÇ ÇÁ·Î±×·¥À» ½ÇÇàÇغ¸°Ú½À´Ï´Ù. $ ./a.out 4 6 a=4, b=0, r=100 °á°ú°ªÀº ¸ÂÁö¸¸ bÀÇ °ªÀÌ 0À¸·Î Ãâ·ÂµË´Ï´Ù. ÀÌ´Â mull instructionÀÌ °á°ú°ªÀ» %edx¿Í %eax¿¡ °ÉÃÄ ÀúÀåÇϱ⠶§¹®ÀÔ´Ï´Ù. À§ÂÊ °á°ú°ªÀÎ %edx°¡ 0ÀÌ µÇÁö¸¸ ÄÄÆÄÀÏ·¯´Â ±× °ªÀÌ º¯ÇÏÁö ¾Ê¾Ò´Ù°í »ý°¢Çϱ⠶§¹®¿¡ bÀÇ °ªÀÌ ¾û¶×ÇÏ°Ô µÈ °Í ÀÔ´Ï´Ù. ÀÌó·³ input, output ¾î´À °ÍÀ¸·Îµµ ¾²ÀÌÁö ¾ÊÁö¸¸ ±× °ªÀÌ º¯ÇÏ´Â °æ¿ì¿¡´Â clobber list¿¡ ±× ·¹Áö½ºÅÍÀÇ À̸§À» Àû¾îÁÖ¸é µË´Ï´Ù. #include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { int a, b, r; a = atoi(argv[1]); b = atoi(argv[2]); __asm__ __volatile__( "movl %1, %%eax \n\t" "addl %2, %%eax \n\t" "mull %%eax " : "=&a" (r) : "g" (a), "g" (b) : "edx" ); printf("a=%d, b=%d, r=%d\n", a, b, r); return 0; } ÄÄÆÄÀÏµÈ °á°ú´Â ´ÙÀ½°ú °°½À´Ï´Ù. .file "clobber_list.c" .version "01.01" gcc2_compiled.: .section .rodata .LC0: .string "a=%d, b=%d, r=%d\n" .text .align 4 .globl main .type main,@function main: pushl %esi pushl %ebx movl 16(%esp),%ebx pushl $0 pushl $10 pushl $0 pushl 4(%ebx) call __strtol_internal movl %eax,%esi addl $16,%esp pushl $0 pushl $10 pushl $0 pushl 8(%ebx) call __strtol_internal movl %eax,%ecx addl $16,%esp #APP movl %esi, %eax addl %ecx, %eax mull %eax #NO_APP pushl %eax pushl %ecx pushl %esi pushl $.LC0 call printf xorl %eax,%eax addl $16,%esp popl %ebx popl %esi ret .Lfe1: .size main,.Lfe1-main .ident "GCC: (GNU) 2.95.4 20010902 (Debian prerelease)" bÀÇ °ªÀ» ecx·Î ÇÒ´çÇÑ °ÍÀ» º¼ ¼ö ÀÖ½À´Ï´Ù. ¹°·Ð °á°ú°ªµµ Á¦´ë·Î ³ª¿É´Ï´Ù. $ ./a.out 6 4 a=6, b=4, r=100 À§ÀÇ ¿¹¿¡¼­ º¼ ¼ö ÀÖµíÀÌ clobber list¿¡´Â ·¹Áö½ºÅÍÀÇ À̸§À» Á÷Á¢ Àû½À´Ï´Ù. ¾²ÀÌ´Â À̸§µéÀº ´ÙÀ½°ú °°½À´Ï´Ù. i386 specific ah, al, ax, eax bh, bl, bx, ebx ch, cl, cx, ecx dh, dl, dx, edx si, esi di, edi (floating ·¹Áö½ºÅ͵éÀº ¾î¶»°Ô ÁöÁ¤ÇÏ´Â Áö ¸ð¸£°Ú½À´Ï´Ù. ¾Æ½Ã´Â ºÐ?) Condition codeÀÇ °ªÀÌ ¹Ù²ñÀ» ³ªÅ¸³»´Â cc°¡ ÀÖÁö¸¸, ix86¿¡¼± ÇÊ¿äÇÏÁö ¾Ê½À´Ï´Ù. ¶Ç, stack, frame pointerÀÎ esp/sp, ebp/bpµµ ÁöÁ¤Àº ÇÒ ¼ö ÀÖÁö¸¸ ¾Æ¹«·± È¿·Âµµ ¾ø½À´Ï´Ù. esp, ebpÀÇ °ªÀ» º¯°æÇÏ´Â °æ¿ì¿£ ¿ø·¡ÀÇ °ªÀ¸·Î º¹¿øÇؾßÇÕ´Ï´Ù.
Applications ÀÌ Ã©ÅÍ¿¡¼± inline assembly¸¦ »ç¿ëÇÏ´Â ¸î°¡Áö ¿¹µéÀ» º¸ÀÌ°Ú½À´Ï´Ù.
Atomic bit operations & spin lock Multithread ÇÁ·Î±×·¥¿¡¼­ °¡Àå Å« ¹®Á¦°¡ µ¿½Ã¿¡ ½ÇÇàÇÏ´Â ¿©·¯°³ÀÇ thread°£ÀÇ µ¿±âÈ­ÀÔ´Ï´Ù. UPÀÇ °æ¿ì ±âº»ÀûÀ¸·Î ¾î´À ½ÃÁ¡¿¡ controlÀ» ´Ù¸¥ thread·Î ³Ñ±æ Áö¸¦ ¾Ë ¼ö ÀÖÀ¸¹Ç·Î ÇÁ·Î¼¼¼­ÀÇ º°´Ù¸¥ Áö¿ø¾øÀ̵µ µ¿±âÈ­°¡ °¡´ÉÇÏÁö¸¸ MP¿¡¼± µ¿½Ã¿¡ ÀÛµ¿ÇÏ´Â ¿©·¯°³ÀÇ ÇÁ·Î¼¼¼­µéÀ» µ¿±âÈ­½ÃÅ°·Á¸é Ư¼öÇÑ ±â´ÉÀ» Á¦°øÇؾßÇÕ´Ï´Ù. ±âº»ÀûÀ¸·Ð ¸Þ¸ð¸®ÀÇ ¾î¶² °ªÀ» Àо Á¶°ÇÀ» È®ÀÎÇÏ°í ±× °ª¿¡ ¾î¶² º¯È­¸¦ ÁÖ´Â ÀÛ¾÷À» atomicÇÏ°Ô ¼öÇàÇÒ ¼ö ÀÖ¾î¾ßÇÕ´Ï´Ù. º¸Åë test and set bitÀ̳ª exchangeµîÀ» atomicÇÏ°Ô ¼öÇàÇÏ´Â ±â´ÉÀ» Á¦°øÇÏ°Ô µÇ´Âµ¥ ix86¿¡¼± µÎ°¡Áö ¸ðµÎ Áö¿øµË´Ï´Ù. (ix86¿¡¼± instruction¿¡ LOCK prefix¸¦ ºÙÀÌ¸é ´ëºÎºÐÀÇ instructionµéÀ» atomicÇÏ°Ô ¼öÇàÇÒ ¼ö ÀÖ½À´Ï´Ù.) ÀÌ Àý¿¡¼± atomic test and set bitÀ» ÀÌ¿ëÇØ µ¿±âÈ­ÀÇ ±âº»ÀûÀÎ ±¸¼º¿ä¼ÒÀÎ spin lockÀ» ¸¸µé¾îº¸°Ú½À´Ï´Ù. Pthread¸¦ »ç¿ëÇØ ¸î°³ÀÇ threadµé »çÀÌ¿¡¼­ spinÀ» ÀÌ¿ëÇÑ µ¿±âÈ­¸¦ Çغ¼ÅÙµ¥, °¢°¢ÀÇ threadµéÀÌ µ¶¸³µÈ processor¿¡¼­ ÀÛµ¿ÇÏ´Â °ÍÀÌ ¾Æ´Ï¶ó time sliceµÇ¾î ÀÛµ¿Çϱ⠶§¹®¿¡ spinÀ» »ç¿ëÇÏ´Â °ÍÀº ÁÁÀº »ý°¢Àº ¾Æ´Õ´Ï´Ù. ¿¹¸¦ µé±âÀ§ÇÑ °ÍÀ̶ó°í »ý°¢ÇϽñ⠹ٶø´Ï´Ù. #include <stdio.h> #include <pthread.h> #include <time.h> static __inline__ int test_and_set_bit(int nr, volatile void *addr) { int oldbit; __asm__ __volatile__( "lock \n\t" "btsl %2, %1 \n\t" "sbbl %0, %0 " : "=r" (oldbit), "=m" (*(unsigned *)addr) : "Ir" (nr)); return oldbit; } typedef unsigned spin_t; static __inline__ void spin_lock(spin_t *spin) { if (test_and_set_bit(0, spin)) while (*(__volatile__ spin_t *)spin) ; } static __inline__ void spin_unlock(spin_t *spin) { *(__volatile__ spin_t *)spin = 0; } spin_t spin = 0; static __inline__ void waste_time(void) { time_t ltime; ltime = time(NULL); while (time(NULL) == ltime) ; } #define pp(fmt, arg...) printf("thread %d : "fmt, thread_no , ##arg) static void * thread_func(void *_arg) { int thread_no = (int)_arg; while (1) { pp("wasting time\n"); waste_time(); pp("entering critical section\n"); pp("now in critical section, wasting time\n"); waste_time(); pp("leaving critical section\n"); } return NULL; } static void * thread_sfunc(void *_arg) { int thread_no = (int)_arg; time_t ltime; while (1) { pp("wasting time\n"); waste_time(); pp("entering critical section\n"); spin_lock(&spin); pp("now in critical section, wasting time\n"); waste_time(); pp("leaving critical section\n"); spin_unlock(&spin); } return NULL; } int main(void) { pthread_t thread0, thread1, thread2, thread3; pthread_create(&thread0, NULL, thread_func, (void *)0); pthread_create(&thread1, NULL, thread_func, (void *)1); pthread_create(&thread2, NULL, thread_sfunc, (void *)2); pthread_create(&thread3, NULL, thread_sfunc, (void *)3); pthread_join(thread0, NULL); pthread_join(thread1, NULL); pthread_join(thread2, NULL); pthread_join(thread3, NULL); return 0; } 4°³ÀÇ thread°¡ ½Ã°£º¸³»±â, critical sectionµé¾î°¡±â, ½Ã°£º¸³»±â, critical section³ª¿À±âÀÇ °úÁ¤À» ¹Ýº¹ÇÕ´Ï´Ù. 0¹ø°ú 1¹ø thread´Â ¾Æ¹«·± µ¿±âÈ­µµ ÇÏÁö ¾Ê°í 2, 3Àº spinÀ» ÀÌ¿ëÇØ critical sectionÀ» º¸È£ÇÕ´Ï´Ù. ¿ì¼± test_and_set_bit ÇÔ¼ö¸¦ »ìÆ캸µµ·Ï ÇÏ°Ú½À´Ï´Ù. lock; btsl %2, %1 AtomicÇÏ°Ô *addrÀÇ nr¹ø° bitÀ» test and setÇÕ´Ï´Ù. TestÀÇ °á°ú´Â carry flag¿¡ ±â·ÏÀ̵˴ϴÙ. sbbl %0, %0 À§ÀÇ btsl¿¡¼­ CF±â·ÏµÈ test°á°ú¸¦ %0¿¡ ÀúÀåÇÕ´Ï´Ù. sbblÀº subtraction with carry·Î À§Ã³·³ °°Àº µÎ ¼ö·Î ½ÇÇàÇϸé carry flag°ú °°Àº ³í¸®°ªÀÌ operand¿¡ ÀúÀåµË´Ï´Ù. Output, input ÁöÁ¤¿¡¼± nrÀÇ constrait°¡ "Ir"ÀÎ Á¡À» Á¦¿ÜÇÏ¸é º°´Ù¸¥ Á¡Àº ¾ø½À´Ï´Ù. nrÀÌ ÇÑ word¾È¿¡¼­ÀÇ bit offsetÀ̹ǷΠimmediateÀÏ ¶§ 0~31»çÀÌ·Î Á¦ÇÑÀ» µÐ °ÍÀÌ°í, ·¹Áö½ºÅÍ operandÀÏ ¶§´Â ÄÄÆÄÀÏŸÀÓ¿¡ È®ÀÎÇÒ ¼ö ¾ø±â ¶§¹®¿¡ ±×³É 'r'À» constraint·Î ÁØ °ÍÀÔ´Ï´Ù. test_and_set_bitÀÌ ÀÖÀ¸¸é spinÀÇ ±¸ÇöÀº °£´ÜÇѵ¥¿ä. test_and_set_bitÀÇ °á°ú°ªÀÌ 0ÀÏ ¶§±îÁö ¹Ýº¹ÀûÀ¸·Î ¼öÇàÇÏ¸é µË´Ï´Ù. À§ÀÇ ÇÁ·Î±×·¥¿¡¼­ ±â´Ù¸®´Â ºÎºÐÀ» while·Î ó¸®ÇÑ °ÍÀº lock; btslº¸´Ù º¸ÅëÀÇ memory read°¡ bus¿¡ ºÎ´ãÀ» ´ú Áֱ⠶§¹®ÀÔ´Ï´Ù. whileÀÇ Á¶°Ç¿¡¼­ __volatile__·Î ij½ºÆÃÈÄ »ç¿ëÇÏ´Â °Ç gcc°¡ ·¹Áö½ºÅÍ¿¡ spinÀÇ °ªÀ» ÀÐÀº ÈÄ ±× °ªÀ» °è¼Ó testÇÏ´Â °ÍÀ» ¸·±â À§Çؼ­ ÀÔ´Ï´Ù. Gcc¿¡°Ô ÀÌ °ªÀº ÇöÀç ÇÁ·Î±×·¥ÀÇ ÁøÇà°ú °ü°è¾øÀÌ ¹Ù²ð ¼ö ÀÖ´Ù´Â °ÍÀ» ¾Ë·ÁÁÖ´Â °ÍÀÔ´Ï´Ù. UnlockÀº ±×³É spinÀÇ °ªÀ» 0À¸·Î ÇÏ¸é µË´Ï´Ù. ¿ª½Ã memory¿¡ Á÷Á¢¾²µµ·Ï ÇϱâÀ§ÇØ __volatile__·Î ij½ºÆÃÈÄ »ç¿ëÇÏ´Â °ÍÀ» º¼ ¼ö ÀÖ½À´Ï´Ù. ±×³É spinÀ» __volatile__·Î ÁöÁ¤ÇØÁ־ µË´Ï´Ù. Inline assembly´Â ´Ü¼øÇϹǷΠÄÄÆÄÀÏµÈ assembly´Â »ý·«ÇÏ°í ½ÇÇà °á°ú¸¦ º¸°Ú½À´Ï´Ù. thread 0 : wasting time thread 1 : wasting time thread 2 : wasting time thread 3 : wasting time thread 0 : entering critical section thread 0 : now in critical section, wasting time thread 3 : entering critical section thread 3 : now in critical section, wasting time thread 2 : entering critical section thread 1 : entering critical section thread 1 : now in critical section, wasting time thread 1 : leaving critical section thread 1 : wasting time thread 0 : leaving critical section thread 0 : wasting time thread 3 : leaving critical section thread 3 : wasting time thread 2 : now in critical section, wasting time thread 2 : leaving critical section thread 2 : wasting time thread 1 : entering critical section thread 1 : now in critical section, wasting time thread 0 : entering critical section thread 0 : now in critical section, wasting time thread 3 : entering critical section thread 3 : now in critical section, wasting time thread 2 : entering critical section thread 1 : leaving critical section thread 1 : wasting time thread 0 : leaving critical section thread 0 : wasting time thread 3 : leaving critical section thread 3 : wasting time thread 2 : now in critical section, wasting time 0°ú 1ÀÇ critical sectionÀº °ãÄ¡Áö¸¸ 2¿Í 3Àº °ãÄ¡Áö ¾ÊÀ½À» ¾Ë ¼ö ÀÖ½À´Ï´Ù.
Function call with stack switch 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 ¿É¼ÇÀ» ÁÖ¾î ¿øÇÏ´Â Äڵ尡 »ý¼ºµÇ¾ú´ÂÁö¸¦ È®ÀÎÇغ¸´Â °ÍÀÌ ÁÁ½À´Ï´Ù.