· 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
Like winter snow on summer lawn, time past is time gone.


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.0029 sec