· KLDP.org · KLDP.net · KLDP Wiki · KLDP BBS ·
Docbook Sgml/GCC_Inline_Assembly-KLDP

GCC inline assembly guide

GCC inline assembly guide

ÇãÅÂÁØ

2001³â 10¿ù 4ÀÏ

ÀÌ ¹®¼­´Â gcc¿¡¼­ inline assembly¸¦ ¼³¸íÇÕ´Ï´Ù. ¼³¸íÀ̳ª ¿¹Á¦´Â ¸ðµÎ ix86À» ±âÁØÀ¸·Î ÇÏ¸ç ¾²ÀÌ´Â ¾ð¾î´Â cÀÔ´Ï´Ù. GCC manual°ú linux/freeBSD source ¹× ÀÚ½ÅÀÇ °æÇèÀ» ¹ÙÅÁÀ¸·Î ½è½À´Ï´Ù. »ç¿ë¹æ¹ýÁ¤µµÀÇ ¼³¸íº¸´Ù´Â »ç¿ë¿¹¿Í ÀÀ¿ëµéÀ» º¸¿©ÁÖ°í ¼³¸íÇÏ´Â °ÍÀ» ¸ñÇ¥·ÎÇÕ´Ï´Ù.

ÀÌ ¹®¼­¸¦ ÀбâÀ§Çؼ­´Â C¸¦ ´É¼÷ÇÏ°Ô ´Ù·ê ¼ö ÀÖÀ¸¸ç processor(ix86)¿Í assembly¿¡ ´ëÇØ ¾î´ÀÁ¤µµ´Â ¾Ë°í ÀÖ¾î¾ß ÇÕ´Ï´Ù. (todo: ·¹ÆÛ·±½º)

ÀÌ ¹®¼­ÀÇ ÃֽŠ¹öÀüÀº ÀÌ°÷ ¿¡¼­ ±¸ÇÒ ¼ö ÀÖÀ¸¸ç Ʋ¸° Á¡ ÁöÀû, Á¦¾È, Áú¹®µîÀº ¿©±â ¿¡ ÇϽñ⠹ٶø´Ï´Ù.

고친 과정
고침 0.12001-10-04고친이 tj
ÃÖÃÊÀÛ¼º


1장. ¼­¹®

1.1. ÀúÀÛ±Ç Á¤º¸

Copyright (C) 2001 ÇãÅÂÁØ

ÀÌ ¹®¼­´Â GNU Free Documentation License ¹öÀü 1.1 ȤÀº ÀÚÀ¯ ¼ÒÇÁÆ®¿þ¾î Àç´Ü¿¡¼­ ¹ßÇàÇÑ ÀÌÈÄ ÆÇÀÇ ±ÔÁ¤¿¡ µû¸£¸ç ÀúÀ۱ǿ¡ ´ëÇÑ º» »çÇ×ÀÌ ¸í½ÃµÇ´Â ÇÑ ¾î¶°ÇÑ Á¤º¸ ¸Åü¿¡ ÀÇÇÑ º»¹®ÀÇ ÀüÀ糪 ¹ßÃéµµ ¹«»óÀ¸·Î Çã¿ëµË´Ï´Ù.


1.2. Ã¥ÀÓÀÇ ÇÑ°è

º» ÀúÀÚ´Â ¹®¼­ÀÇ ³»¿ëÀÌ ¾ß±âÇÒ ¼ö ÀÖ´Â ¾î¶°ÇÑ °á°ú¿¡ ´ëÇؼ­µµ Ã¥ÀÓÀ» ÁöÁö ¾Ê½À´Ï´Ù. º» ¹®¼­¿¡¼­ ³»Æ÷ÇÏ°í ÀÖ´Â Á¤º¸µé ¹× ¿¹Á¦µéÀº ¿©·¯ºÐÀÌ ¾Ë¾Æ¼­ È°¿ëÇϽʽÿÀ. ºñ·Ï ÃÖ¼±À» ´ÙÇßÀ¸³ª ÀÌ ¹®¼­´Â Ʋ¸° Á¡À̳ª ¿À·ù°¡ ÀÖÀ» ¼öµµ ÀÖ½À´Ï´Ù. ¸¸¾à ¿©·¯ºÐÀÌ Æ²¸° Á¡À» ¹ß°ßÇß´Ù¸é ²À Àú¿¡°Ô ¾Ë·Á Áֽñ⠹ٶø´Ï´Ù.


1.3. 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¿¡¼­ ¾µ ¼ö ÀÖ°í ·¹Áö½ºÅ͵éÀ» ¾î¶»°Ô ´Ù·ê Áö¸¦ ÁöÁ¤ÇÒ ¼öµµ ÀÖ½À´Ï´Ù. Â÷Â÷ »ìÆ캸µµ·Ï ÇÏ°Ú½À´Ï´Ù.


2장. Inline assembly basics

¿ì¼± µÑ·¯º¸±â¿¡¼­ ¿¹Á¦¸¦ ÅëÇØ ¾î¶»°Ô »ý°å°í °¢°¢ÀÇ ºÎºÐÀÇ Àǹ̴ ¹«¾ùÀ̸ç gcc°¡ ÄÄÆÄÀÏÇßÀ» ¶§ ¾î¶² °á°ú¸¦ ³»¾î³õ´Â Áö¸¦ °£´ÜÈ÷ »ìÆ캻 ÈÄ °¢°¢ÀÇ ºÎºÐ¿¡ ´ëÇØ ÀÚ¼¼È÷ ¼³¸íÇÏ°Ú½À´Ï´Ù.


2.1. µÑ·¯º¸±â

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 º¯¼ö Ç׸ñ¿¡¼­ ¼³¸íÇÏ°Ú½À´Ï´Ù.

ÀÌÁ¦ Àüü¸¦ ÇÑ ¹ø º¸¾Ò½À´Ï´Ù. ±×´ÙÁö º¹ÀâÇÏÁö ¾ÊÁö¿ä? ÀÌÁ¦ °¢ ºÎºÐ¿¡´ëÇØ ÀÚ¼¼È÷ ¾Ë¾Æº¸µµ·Ï ÇÏ°Ú½À´Ï´Ù.


2.2. 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À» ÂüÁ¶Çϼ¼¿ä.


2.2.1. µé¿©¾²±â & Ä¿¸àÆ® ´Þ±â

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¿¡¼­µµ °°Àº ¹æ¹ýÀ¸·Î ¾µ ¼ö ÀÖ½À´Ï´Ù.


2.2.2. Register Á÷Á¢ ÁöÁ¤Çϱâ

À§ÀÇ ¿¹¿¡¼­ %%eax, %%esp°°Àº °ÍµéÀ» º¼ ¼ö Àִµ¥ %%´Â ½ÇÁ¦ output¿¡¼­ % Çϳª¸¦ Ãâ·ÂÇÕ´Ï´Ù. ƯÁ¤ ·¹Áö½ºÅ͸¦ ½á¾ßÇÒ ¶§´Â %nÀ¸·Î Á¤ÇØÁ൵ µÇÁö¸¸ input, output ÁöÁ¤¿¡¼­ ¾²°í ½ÍÀº ·¹Áö½ºÅ͸¦ ÁöÁ¤ÇÏ°í ¾îÂ÷ÇÇ ±× ·¹Áö½ºÅÍ°¡ ÇÒ´çµÉ °ÍÀ» ¾Ë°í ÀÖÀ¸¹Ç·Î %%register¸¦ ¾²´Â °ÍÀÌ ´õ ÀÐ°í ¾²±â ÆíÇÕ´Ï´Ù.

ÇÑ °¡Áö ÁÖÀÇÇÒ Á¡Àº ¸¸¾à input, outputÀÌ Çϳªµµ ¾ø´Â °æ¿ì¿¡´Â asms¿¡ ´ëÇÑ ÀÎÀÚġȯÀÌ ÀüÇô ÀϾÁö ¾Ê°í %%µµ %·Î ¹Ù²îÁö ¾Ê½À´Ï´Ù. Áï, input, outputÀÌ ¸ðµÎ ¾øÀ» ¶§´Â %%register´ë½Å %register¶ó°í ÇؾßÇÕ´Ï´Ù.


2.2.3. 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À¸·Î ó¸®µÈ °ÍÀ» º¼ ¼ö ÀÖ½À´Ï´Ù.


2.3. Output/Input List

Output°ú inputÀº "constraint" (variable)µéÀÇ ½°Ç¥·Î ±¸ºÐµÈ ¸®½ºÆ®·Î ±¸¼ºµË´Ï´Ù.

Constraint´Â ¾Æ·¡ÀÇ ¹®ÀÚµé°ú ¸î°¡Áö modifierµéÀÇ Á¶ÇÕÀ¸·Î Çã¿ëµÇ´Â operandÀÇ Á¾·ù¿Í ±× operand°¡ inline assembly¿¡¼­ ¾î¶»°Ô »ç¿ëµÇ´ÂÁö¸¦ ³ªÅ¸³À´Ï´Ù. ¾Æ·¡ÀÇ ¸®½ºÆ®´Â ¿ÏÀüÇÏÁö ¾Ê½À´Ï´Ù. Gcc ¸Þ´º¾óÀ» ÂüÁ¶Çϼ¼¿ä.


2.3.1. Constraints

2.3.1.1. 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.


2.3.1.2. 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


2.3.1.3. Modifiers

Constraint modifierµéÀº ±× º¯¼ö°¡ ¾î¶»°Ô »ç¿ëµÇ´Â Áö¸¦ compiler¿¡°Ô ¾Ë·ÁÁÝ´Ï´Ù. ¾Æ·¡ÀÇ ¸®½ºÆ®´Â ¿ÏÀüÇÏÁö ¾Ê½À´Ï´Ù. Gcc ¸Þ´º¾óÀ» ÂüÁ¶Çϼ¼¿ä.

'='

º¯¼öÀÇ °ªÀÌ ¹Ù²ñÀ» ³ªÅ¸³À´Ï´Ù. Outputµé¿¡ ´ëÇؼ­´Â ÀÌ modifier°¡ ¹Ýµå½Ã ÁöÁ¤µÇ¾î ÀÖ¾î¾ß ÇÕ´Ï´Ù.

'&'

Early clobber. ´ÙÀ½ Àý¿¡¼­ ÀÚ¼¼È÷ ¼³¸íÇÏ°Ú½À´Ï´Ù.


2.3.2. 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µµ °ãÄ¡°Ô ÇÒ´çµÇÁö ¾Ê¾ÒÀ½À» ¾Ë ¼ö ÀÖ½À´Ï´Ù.


2.4. 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ÀÇ °ªÀ» º¯°æÇÏ´Â °æ¿ì¿£ ¿ø·¡ÀÇ °ªÀ¸·Î º¹¿øÇؾßÇÕ´Ï´Ù.


3장. Applications

ÀÌ Ã©ÅÍ¿¡¼± inline assembly¸¦ »ç¿ëÇÏ´Â ¸î°¡Áö ¿¹µéÀ» º¸ÀÌ°Ú½À´Ï´Ù.


3.1. 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Àº °ãÄ¡Áö ¾ÊÀ½À» ¾Ë ¼ö ÀÖ½À´Ï´Ù.


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


ID
Password
Join
You will have long and healthy life.


sponsored by andamiro
sponsored by cdnetworks
sponsored by HP

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2011-11-10 09:49:11
Processing time 0.0056 sec