<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wikidot="http://www.wikidot.com/rss-namespace">

	<channel>
		<title>as:rss</title>
		<link>http://ccckmit.wikidot.com</link>
		<description>陳鍾誠的首頁 -- 金門大學 資訊工程系</description>
				<copyright></copyright>
		<lastBuildDate>Sun, 16 Aug 2026 16:21:37 +0000</lastBuildDate>
		
					<item>
				<guid>http://ccckmit.wikidot.com/as:main</guid>
				<title>免費電子書 -- 組合語言</title>
				<link>http://ccckmit.wikidot.com/as:main</link>
				<description>

&lt;p&gt;在電腦越來越發達的時代，程式設計師與組合語言的距離就越來越遠了，這往往讓我們不知道如何在個人電腦上撰寫組合語言。對於那些曾經碰過 DOS 系統的人而言，撰寫組合語言是常見的事情，但是自從 Windows 加入保護功能之後，這些 DOS 的組合語言就再也不能執行了，要在 Windows 系統下撰寫組合語言，成了一種很少人會的絕技。&lt;/p&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=296763&amp;amp;amp;size=small&amp;amp;amp;timestamp=1786897297&quot; alt=&quot;ccckmit&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=296763)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;ccckmit&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Mon, 11 Oct 2010 05:54:28 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>在電腦越來越發達的時代，程式設計師與組合語言的距離就越來越遠了，這往往讓我們不知道如何在個人電腦上撰寫組合語言。對於那些曾經碰過 DOS 系統的人而言，撰寫組合語言是常見的事情，但是自從 Windows 加入保護功能之後，這些 DOS 的組合語言就再也不能執行了，要在 Windows 系統下撰寫組合語言，成了一種很少人會的絕技。</p> <p>其實，要在個人電腦的 MS. Windows 系統上撰寫組合語言，並不是那麼困難的，只要您善用組合語言的開發工具，像是微軟的 ml.exe (俗稱 MASM)，以及 GNU 的 gcc、as 等程式，就可以在 MS. Windows 系統中撰寫 x86 平台的組合語言了。</p> <p>但必須注意的是，在 MS. Windows 系統上撰寫組合語言時，不要再採用過去在 DOS 當中所使用的方式，用 int 10h 呼叫 BIOS 中斷，或者用 int 21h 執行 DOS 的系統呼叫，這些都是不正確的方式。如果您採用微軟的 ml 組譯器，請連結微軟系統中的 LIBCMT 函式庫，其中有 C 語言所使用的 printf 函數，直接透過這個函數進行輸出入即可，以下是筆者所撰寫的組合語言程式，可以計算並印出 1+2+&#8230;+10 的結果。</p> <p>範例一：計算 1+2+&#8230;+10</p> <div class="code"> <pre><code>.386 .model flat INCLUDELIB LIBCMT printf PROTO C, format:PTR BYTE, args:VARARG .data sum DWORD 0 formatStr BYTE &quot;sum=%d&quot;, 0dh, 0ah, 0 PUBLIC _main .code _main PROC MOV eax, 1 FOR1: ADD sum, eax ADD eax, 1 CMP eax, 10 JLE FOR1 INVOKE printf, ADDR formatStr, sum ret 0 _main ENDP END</code></pre></div> <p>執行結果</p> <div class="code"> <pre><code>D:\code\ASM&gt;ml sum.asm Microsoft (R) Macro Assembler Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. Assembling: sum.asm Microsoft (R) Incremental Linker Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. /OUT:sum.exe sum.obj D:\code\ASM&gt;sum sum=55</code></pre></div> <h1><span>結語</span></h1> <p>這樣撰寫組合語言，其實就相當的輕鬆愉快了，學習組合語言也不再是一個神祕的技巧，只要拋棄過去在 DOS 時代所養成的習慣就行了。在 MS Windows 系統當中，不要再堅持自己用 int 10h 等中斷呼叫進行輸出入了，如此反而能真正學習到組合語言的精神與技巧，不是嗎？</p> <div style="text-align: right;"> <p>陳鍾誠 於 金門大學 2010 年 10 月 12 日</p> </div> <p>by <span class="printuser avatarhover"><a href="http://www.wikidot.com/user:info/ccckmit" ><img class="small" src="http://www.wikidot.com/avatar.php?userid=296763&amp;amp;size=small&amp;amp;timestamp=1786897297" alt="ccckmit" style="background-image:url(http://www.wikidot.com/userkarma.php?u=296763)" /></a><a href="http://www.wikidot.com/user:info/ccckmit" >ccckmit</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://ccckmit.wikidot.com/as:msexample</guid>
				<title>組合語言 -- 微軟的範例</title>
				<link>http://ccckmit.wikidot.com/as:msexample</link>
				<description>

&lt;p&gt;在電腦越來越發達的時代，程式設計師與組合語言的距離就越來越遠了，這往往讓我們不知道如何在個人電腦上撰寫組合語言。對於那些曾經碰過 DOS 系統的人而言，撰寫組合語言是常見的事情，但是自從 Windows 加入保護功能之後，這些 DOS 的組合語言就再也不能執行了，要在 Windows 系統下撰寫組合語言，成了一種很少人會的絕技。&lt;/p&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=296763&amp;amp;amp;size=small&amp;amp;amp;timestamp=1786897297&quot; alt=&quot;ccckmit&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=296763)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;ccckmit&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Tue, 12 Oct 2010 09:25:36 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>在電腦越來越發達的時代，程式設計師與組合語言的距離就越來越遠了，這往往讓我們不知道如何在個人電腦上撰寫組合語言。對於那些曾經碰過 DOS 系統的人而言，撰寫組合語言是常見的事情，但是自從 Windows 加入保護功能之後，這些 DOS 的組合語言就再也不能執行了，要在 Windows 系統下撰寫組合語言，成了一種很少人會的絕技。</p> <p>但是，其實在 MS. Windows 之下撰寫組合語言並沒有那麼困難。要在微軟的平台上撰寫組合語言，最簡單的方式是安裝 Visual Studio Professional，然後啟動 Visual Studio 的命令列工具，舉例而言，在筆者的電腦上安裝有 Windows XP + Visual Studio Professional 2008，筆者只要啟動「開始/所有程式/Microsoft Visual Studio 2008/Visual Studio Tools/Visual Studio 2008 命令提是字元」後，就可以打入 ml 指令看看是否具有微軟的組譯器 ml.exe，如下圖所示。</p> <div class="image-container aligncenter"><img src="http://ccckmit.wdfiles.com/local--files/as:msexample/ml.png" alt="ml.png" class="image" /></div> <p style="text-align: center;">圖一、測試微軟的組譯器是否存在</p> <p>一但有了這個組譯器，您就可以開始撰寫微軟的組合語言了，以下是一些組合語言的程式範例，以及筆者的執行情況。</p> <h1><span>範例一、加減法</span></h1> <p>檔案：add.asm</p> <div class="code"> <pre><code>.386 .model flat INCLUDELIB LIBCMT printf PROTO C, format:PTR BYTE, args:VARARG .data num DWORD 0 formatStr BYTE &quot;num=%d&quot;, 0dh, 0ah, 0 PUBLIC _main .code _main PROC MOV eax, 1 ADD eax, 4 SUB eax, 2 MOV num, eax INVOKE printf, ADDR formatStr, num ret 0 _main ENDP END</code></pre></div> <p>執行結果</p> <div class="code"> <pre><code>D:\code\ASM&gt;ml add.asm Microsoft (R) Macro Assembler Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. Assembling: add.asm Microsoft (R) Incremental Linker Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. /OUT:add.exe add.obj D:\code\ASM&gt;add num=3</code></pre></div> <h1><span>範例二、計算總和</span></h1> <p>檔案：sum.asm</p> <div class="code"> <pre><code>.386 .model flat INCLUDELIB LIBCMT printf PROTO C, format:PTR BYTE, args:VARARG .data sum DWORD 0 formatStr BYTE &quot;sum=%d&quot;, 0dh, 0ah, 0 PUBLIC _main .code _main PROC MOV eax, 1 FOR1: ADD sum, eax ADD eax, 1 CMP eax, 10 JLE FOR1 INVOKE printf, ADDR formatStr, sum ret 0 _main ENDP END</code></pre></div> <p>執行結果</p> <div class="code"> <pre><code>D:\code\ASM&gt;ml sum.asm Microsoft (R) Macro Assembler Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. Assembling: sum.asm Microsoft (R) Incremental Linker Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. /OUT:sum.exe sum.obj D:\code\ASM&gt;sum sum=55</code></pre></div> <p>by <span class="printuser avatarhover"><a href="http://www.wikidot.com/user:info/ccckmit" ><img class="small" src="http://www.wikidot.com/avatar.php?userid=296763&amp;amp;size=small&amp;amp;timestamp=1786897297" alt="ccckmit" style="background-image:url(http://www.wikidot.com/userkarma.php?u=296763)" /></a><a href="http://www.wikidot.com/user:info/ccckmit" >ccckmit</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://ccckmit.wikidot.com/as:related</guid>
				<title>組合語言 -- 相關訊息</title>
				<link>http://ccckmit.wikidot.com/as:related</link>
				<description>

&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=296763&amp;amp;amp;size=small&amp;amp;amp;timestamp=1786897297&quot; alt=&quot;ccckmit&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=296763)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;ccckmit&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Mon, 11 Oct 2010 08:08:08 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>by <span class="printuser avatarhover"><a href="http://www.wikidot.com/user:info/ccckmit" ><img class="small" src="http://www.wikidot.com/avatar.php?userid=296763&amp;amp;size=small&amp;amp;timestamp=1786897297" alt="ccckmit" style="background-image:url(http://www.wikidot.com/userkarma.php?u=296763)" /></a><a href="http://www.wikidot.com/user:info/ccckmit" >ccckmit</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://ccckmit.wikidot.com/as:ref</guid>
				<title>組合語言 -- 參考文獻</title>
				<link>http://ccckmit.wikidot.com/as:ref</link>
				<description>

&lt;ol&gt;
&lt;li&gt;Wikipedia:Assembly language &amp;#8212; &lt;a href=&quot;http://en.wikipedia.org/wiki/Assembly_language&quot;&gt;http://en.wikipedia.org/wiki/Assembly_language&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;維基百科:組合語言 &amp;#8212; &lt;a href=&quot;http://zh.wikipedia.org/zh-tw/%E6%B1%87%E7%BC%96%E8%AF%AD%E8%A8%80&quot;&gt;http://zh.wikipedia.org/zh-tw/%E6%B1%87%E7%BC%96%E8%AF%AD%E8%A8%80&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=296763&amp;amp;amp;size=small&amp;amp;amp;timestamp=1786897297&quot; alt=&quot;ccckmit&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=296763)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;ccckmit&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Mon, 11 Oct 2010 08:07:00 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <ol> <li>Wikipedia:Assembly language &#8212; <a href="http://en.wikipedia.org/wiki/Assembly_language">http://en.wikipedia.org/wiki/Assembly_language</a></li> <li>維基百科:組合語言 &#8212; <a href="http://zh.wikipedia.org/zh-tw/%E6%B1%87%E7%BC%96%E8%AF%AD%E8%A8%80">http://zh.wikipedia.org/zh-tw/%E6%B1%87%E7%BC%96%E8%AF%AD%E8%A8%80</a></li> </ol> <p>by <span class="printuser avatarhover"><a href="http://www.wikidot.com/user:info/ccckmit" ><img class="small" src="http://www.wikidot.com/avatar.php?userid=296763&amp;amp;size=small&amp;amp;timestamp=1786897297" alt="ccckmit" style="background-image:url(http://www.wikidot.com/userkarma.php?u=296763)" /></a><a href="http://www.wikidot.com/user:info/ccckmit" >ccckmit</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://ccckmit.wikidot.com/as:site</guid>
				<title>組合語言 -- 相關網站</title>
				<link>http://ccckmit.wikidot.com/as:site</link>
				<description>

&lt;ol&gt;
&lt;li&gt;Assembly Language for x86 Processors, 6th edition &amp;#8212; &lt;a href=&quot;http://kipirvine.com/asm/&quot;&gt;http://kipirvine.com/asm/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PC Assembly Language &amp;#8212; &lt;a href=&quot;http://www.drpaulcarter.com/pcasm/&quot;&gt;http://www.drpaulcarter.com/pcasm/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;小木偶的網頁 (組合語言) &amp;#8212; &lt;a href=&quot;http://home.educities.edu.tw/wanker742126/&quot;&gt;http://home.educities.edu.tw/wanker742126/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;組合語言程式設計 &amp;#8212; &lt;a href=&quot;http://masm1215.myweb.hinet.net/menu.htm&quot;&gt;http://masm1215.myweb.hinet.net/menu.htm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格致中學 (組合語言) &amp;#8212; &lt;a href=&quot;http://www.gjsh.tpc.edu.tw/electronic/teach/asm_home.htm&quot;&gt;http://www.gjsh.tpc.edu.tw/electronic/teach/asm_home.htm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;程式設計俱樂部 (組合語言) &lt;a href=&quot;http://www.programmer-club.com.tw/pc2020v5/kb/kb_default.asp?board_pc2020=assembly&quot;&gt;http://www.programmer-club.com.tw/pc2020v5/kb/kb_default.asp?board_pc2020=assembly&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=296763&amp;amp;amp;size=small&amp;amp;amp;timestamp=1786897297&quot; alt=&quot;ccckmit&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=296763)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;ccckmit&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Mon, 11 Oct 2010 08:03:19 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <ol> <li>Assembly Language for x86 Processors, 6th edition &#8212; <a href="http://kipirvine.com/asm/">http://kipirvine.com/asm/</a></li> <li>PC Assembly Language &#8212; <a href="http://www.drpaulcarter.com/pcasm/">http://www.drpaulcarter.com/pcasm/</a></li> <li>小木偶的網頁 (組合語言) &#8212; <a href="http://home.educities.edu.tw/wanker742126/">http://home.educities.edu.tw/wanker742126/</a></li> <li>組合語言程式設計 &#8212; <a href="http://masm1215.myweb.hinet.net/menu.htm">http://masm1215.myweb.hinet.net/menu.htm</a></li> <li>格致中學 (組合語言) &#8212; <a href="http://www.gjsh.tpc.edu.tw/electronic/teach/asm_home.htm">http://www.gjsh.tpc.edu.tw/electronic/teach/asm_home.htm</a></li> <li>程式設計俱樂部 (組合語言) <a href="http://www.programmer-club.com.tw/pc2020v5/kb/kb_default.asp?board_pc2020=assembly">http://www.programmer-club.com.tw/pc2020v5/kb/kb_default.asp?board_pc2020=assembly</a></li> </ol> <p>by <span class="printuser avatarhover"><a href="http://www.wikidot.com/user:info/ccckmit" ><img class="small" src="http://www.wikidot.com/avatar.php?userid=296763&amp;amp;size=small&amp;amp;timestamp=1786897297" alt="ccckmit" style="background-image:url(http://www.wikidot.com/userkarma.php?u=296763)" /></a><a href="http://www.wikidot.com/user:info/ccckmit" >ccckmit</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://ccckmit.wikidot.com/as:gnu</guid>
				<title>組合語言 -- GNU 開發工具</title>
				<link>http://ccckmit.wikidot.com/as:gnu</link>
				<description>

&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=296763&amp;amp;amp;size=small&amp;amp;amp;timestamp=1786897297&quot; alt=&quot;ccckmit&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=296763)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;ccckmit&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Mon, 11 Oct 2010 07:59:26 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>by <span class="printuser avatarhover"><a href="http://www.wikidot.com/user:info/ccckmit" ><img class="small" src="http://www.wikidot.com/avatar.php?userid=296763&amp;amp;size=small&amp;amp;timestamp=1786897297" alt="ccckmit" style="background-image:url(http://www.wikidot.com/userkarma.php?u=296763)" /></a><a href="http://www.wikidot.com/user:info/ccckmit" >ccckmit</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://ccckmit.wikidot.com/as:basic</guid>
				<title>組合語言簡介</title>
				<link>http://ccckmit.wikidot.com/as:basic</link>
				<description>

&lt;p&gt;在電腦發展的早期，許多人都會使用組合語言撰寫程式。但在電腦發達的今天，組合語言通常只被用來撰寫非常低階的程式，像是啟動載入器、配置中斷向量、作業系統的行程切換、驅動程式、以及少數為了速度原因而採用組合語言的程式，例如像繪圖卡的顯示程式等。&lt;/p&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=296763&amp;amp;amp;size=small&amp;amp;amp;timestamp=1786897297&quot; alt=&quot;ccckmit&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=296763)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;ccckmit&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Mon, 11 Oct 2010 07:58:39 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>在電腦發展的早期，許多人都會使用組合語言撰寫程式。但在電腦發達的今天，組合語言通常只被用來撰寫非常低階的程式，像是啟動載入器、配置中斷向量、作業系統的行程切換、驅動程式、以及少數為了速度原因而採用組合語言的程式，例如像繪圖卡的顯示程式等。</p> <p>雖然如此，學習組合語言的概念仍然有其重要性。因為組合語言除了是計算機結構的核心領域，可以幫助理解電腦的硬體架構之外，還可以幫助讀者學習系統軟體的設計方式，是理解系統軟體的捷徑。正因為如此，組合語言可以說是系統程式課程的核心，</p> <p>by <span class="printuser avatarhover"><a href="http://www.wikidot.com/user:info/ccckmit" ><img class="small" src="http://www.wikidot.com/avatar.php?userid=296763&amp;amp;size=small&amp;amp;timestamp=1786897297" alt="ccckmit" style="background-image:url(http://www.wikidot.com/userkarma.php?u=296763)" /></a><a href="http://www.wikidot.com/user:info/ccckmit" >ccckmit</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://ccckmit.wikidot.com/as:cpu</guid>
				<title>組合語言 -- 處理器</title>
				<link>http://ccckmit.wikidot.com/as:cpu</link>
				<description>

&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;http://ccckmit.wikidot.com/as:x86&quot;&gt;個人電腦的 x86 處理器架構&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://ccckmit.wikidot.com/as:arm&quot;&gt;手機常用的 ARM 處理器架構&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=296763&amp;amp;amp;size=small&amp;amp;amp;timestamp=1786897297&quot; alt=&quot;ccckmit&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=296763)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;ccckmit&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Mon, 11 Oct 2010 07:56:33 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <ol> <li><a href="http://ccckmit.wikidot.com/as:x86">個人電腦的 x86 處理器架構</a></li> <li><a href="http://ccckmit.wikidot.com/as:arm">手機常用的 ARM 處理器架構</a></li> </ol> <p>by <span class="printuser avatarhover"><a href="http://www.wikidot.com/user:info/ccckmit" ><img class="small" src="http://www.wikidot.com/avatar.php?userid=296763&amp;amp;size=small&amp;amp;timestamp=1786897297" alt="ccckmit" style="background-image:url(http://www.wikidot.com/userkarma.php?u=296763)" /></a><a href="http://www.wikidot.com/user:info/ccckmit" >ccckmit</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://ccckmit.wikidot.com/as:inlinec</guid>
				<title>組合語言 -- 在 C 語言當中內嵌組合語言</title>
				<link>http://ccckmit.wikidot.com/as:inlinec</link>
				<description>

&lt;p&gt;有時，為了能增進程式的效率，或者在 C 語言當中加入一些組合語言程式碼，我們會採用內嵌的方式，將組合語言內嵌在C語言當中。針對這點，gcc提供了如圖 4.10的內嵌語法，讓我們在 C 語言中可以直接撰寫組合語言。其中，assembler template 為組合語言程式、output operands 為輸入參數、input operands 為輸入參數，而 list of clobbered registers 則指定了被更改的暫存器參數列表。&lt;/p&gt;
&lt;div class=&quot;code&quot;&gt;
&lt;pre&gt;&lt;code&gt;asm(                                   ; 內嵌起始符號
     assembler template                ; 組合語言程式
     : output operands                 ; : 輸出參數列表
     : input operands                  ; : 輸入參數列表
     : list of clobbered registers     ; : 被更改的暫存器列表
     );                                ; 結束符號&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;圖 4.10GNU 的內嵌組合語言語法&lt;/p&gt;
&lt;p&gt;舉例而言，範例 4.24的C語言程式當中，就內嵌了組合語言。其中，第一欄是內嵌組合語言的C語言程式 inlineAsm1.c，第二欄則是其說明，第三欄是我們利用gcc將該程式轉換成inlineAsm.s 組合語言程式的片段，其中有底線的文字部分對應的是內嵌組合語言的展開部分。&lt;/p&gt;
&lt;p&gt;在GNU的內嵌組合語言 (assembler template) 中，由於 % 被用作參數 %1, %2, … 的前置字元，因此當遇到暫存器(像是 %eax) 時，必須使用兩個 % 符號 (%%) 作為暫存器的起始標記，因此，在範例 4.24中，原本的 addl %ebx, %eax 指令，就成了 addl %%ebx, %%eax 這個更冗長的指令。&lt;/p&gt;
&lt;p&gt;在範例 4.24的內嵌參數部分，:&amp;quot;a&amp;quot;(foo), &amp;quot;b&amp;quot;(bar) 是輸入參數，代表要將 foo 變數傳遞給限制條件為 &amp;quot;a&amp;quot; 的暫存器，由於在 IA32 中限制條件為&amp;quot;a&amp;quot;的暫存器就是 eax，因此，foo 變數將會傳給 eax 暫存器。同理，&amp;quot;b&amp;quot;(bar) 參數代表將 bar 傳給 ebx 暫存器。而輸出參數 :&amp;quot;=a&amp;quot;(foo) 則是將 eax 的結果傳回到 foo 變數中。&lt;/p&gt;
&lt;p&gt;範例 4.24 內嵌組合語言的C程式&lt;/p&gt;
&lt;div class=&quot;code&quot;&gt;
&lt;pre&gt;&lt;code&gt;int main(void)                   ; ...                
{                                ; movl $10, -8(%ebp)       ; foo=-8(%ebp)=10
  int foo = 10, bar = 15;        ; movl $15, -12(%ebp)      ; bar=-12(%ebp)=15
                                 ; 輸入參數：
  asm(                           ; movl -8(%ebp), %eax      ; eax = -8(%ebp)=foo
    &amp;quot;addl %%ebx,%%eax&amp;quot;           ; movl -12(%ebp), %ebx     ; ebx = -12(%ebp)=bar
    :&amp;quot;=a&amp;quot;(foo)                   ; /APP                     ; 嵌入的程式
    :&amp;quot;a&amp;quot;(foo), &amp;quot;b&amp;quot;(bar)          ; addl %ebx,%eax           ; eax = eax+ebx
  );                             ; /NO_APP                  ; 傳出參數
                                 ; movl %eax, -8(%ebp)      ; foo=eax
  printf(&amp;quot;foo=%d\n&amp;quot;, foo);       ; movl -8(%ebp), %eax
  return 0;                      ; movl %eax, 4(%esp)
}                                ; movl $LC0, (%esp)
                                 ; call _printf
                                 ; ...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;請讀者仔細觀察範例 4.24的組合語言程式碼，其中，內嵌指令 asm() 中的輸入參數部分為 :&amp;quot;a&amp;quot;(foo), &amp;quot;b&amp;quot;(bar)。這導致代表foo參數的-8(%ebp)被傳入限制條件 &amp;quot;a&amp;quot; 所對應的 eax暫存器中；而代表bar參數的-12(%ebp)則被傳入限制條件&amp;quot;b&amp;quot;所對應的ebx 暫存器中，然後，才執行內嵌指令 addl %ebx, %eax。在執行完畢之後，輸出參數 :&amp;quot;=a&amp;quot;(foo) 指定將 eax 傳回 foo:-8(%ebp) 變數中，於是最後補上了 movl %eax, -8(%ebp) 指令，完成整個內嵌呼叫的過程。&lt;/p&gt;
&lt;p&gt;範例 4.25顯示了該程式的編譯執行過程，首先，我們利用 gcc 加上 –S 參數，將C語言編譯為組合語言檔案。接著，再利用gcc作為組譯連結器，將inlineAsm1.s組譯並連結為執行檔，然後執行之，結果，foo果然變成 25，這代表嵌入的組合語言程式發揮了效用。&lt;/p&gt;
&lt;p&gt;範例 4.25 &amp;lt;範例 4.24&amp;gt; 的編譯與執行過程&lt;/p&gt;
&lt;div class=&quot;code&quot;&gt;
&lt;pre&gt;&lt;code&gt;$ gcc -S inlineAsm1.c -o inlineAsm1.s  ; 將C程式編譯為組合語言

$ gcc inlineAsm1.s -o inlineAsm1       ; 組譯 inlineAsm1.s 組合語言檔

$ ./inlineAsm1                         ; 執行inlineAsm1 的執行檔
foo=25                                 ; 結果： foo+bar 的值為25&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;在嵌入式組合語言 asm() 的語法中，每個參數的語法為 &amp;quot;限制條件&amp;quot;(變數)，例如範例 4.24中的 &amp;quot;a&amp;quot;(foo), &amp;quot;b&amp;quot;(bar) 等，其中的 &amp;quot;a&amp;quot;, &amp;quot;b&amp;quot; 都是限制條件，而 (foo), (bar) 則是C語言中所傳入傳出的變數。&lt;/p&gt;
&lt;p&gt;限制條件可能代表某一個暫存器、一群暫存器、記憶體變數、或者數值等。例如，限制條件m代表『記憶體運算元』、p代表『合法的位址』，而 g 則代表『通用型暫存器、記憶體位址或立即定址的數值』的集合等等。&lt;/p&gt;
&lt;p&gt;但是，限制條件的設定與CPU的架構有關，同一個符號在不同的CPU中會有不同的意義。例如，在IA32處理器中，限制條件a代表 eax、b 代表 ebx、c代表 ecx、d代表 edx、S 代表 esi、D代表 edi、r代表『eax ebx ecx edx esi edi』的集合、q代表 『eax ebx ecx edx』的集合、g代表『eax,ebx, ecx, edx 或變數』，而 1,則代表與參數 %1 相同, 2 代表與參數 %2 相同 …。&lt;/p&gt;
表格 4.1 GNU嵌入式組合語言的限制條件 (針對 IA32處理器)&lt;br /&gt;
&lt;table class=&quot;wiki-content-table&quot;&gt;
&lt;tr&gt;
&lt;td&gt;限制&lt;/td&gt;
&lt;td&gt;說明&lt;/td&gt;
&lt;td&gt;限制&lt;/td&gt;
&lt;td&gt;說明&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;eax&lt;/td&gt;
&lt;td&gt;I&lt;/td&gt;
&lt;td&gt;(instant constant) 常數 (0到31 之間)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;ebx&lt;/td&gt;
&lt;td&gt;m&lt;/td&gt;
&lt;td&gt;(memory) 記憶體位址&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;ecx&lt;/td&gt;
&lt;td&gt;r&lt;/td&gt;
&lt;td&gt;(register) 暫存器eax ebx ecx edx esi edi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;edx&lt;/td&gt;
&lt;td&gt;q&lt;/td&gt;
&lt;td&gt;eax ebx ecx edx&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S&lt;/td&gt;
&lt;td&gt;esi&lt;/td&gt;
&lt;td&gt;g&lt;/td&gt;
&lt;td&gt;(general) eax,ebx, ecx, edx、變數或常數&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;edi&lt;/td&gt;
&lt;td&gt;0, 1, 2, …&lt;/td&gt;
&lt;td&gt;參數 %0 %1 %2 &amp;#8230;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;…&lt;/td&gt;
&lt;td&gt;…&lt;/td&gt;
&lt;td&gt;…&lt;/td&gt;
&lt;td&gt;…&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;利用表格 4.1中的限制條件，我們可以放寬暫存器的限制，改使用像 addl %2, %0 這樣的方式。這種方式可以讓編譯器自行選擇能使用的暫存器，如此，可以增進程式的效率。在範例 4.26中，我們就使用了此種參數指定的方式，利用 addl %2, %0 指令內嵌，然後，在輸出參數0 中指定 :&amp;quot;=r&amp;quot;(foo)，這使得 foo 可使用的候選的暫存器放寬為 r 條件的『eax ebx ecx edx esi edi』。接著，在輸入參數 %1, %2中指定 :&amp;quot;0&amp;quot;(foo), &amp;quot;r&amp;quot;(bar)，這同樣使得 bar 的候選暫存器放寬為r 條件的『eax ebx ecx edx esi edi』。但是，由於 foo 變數已經在輸出參數 :&amp;quot;=r&amp;quot;(foo)被指定了，因此，必須在第一個輸入參數的 (foo) 前加上 &amp;quot;0&amp;quot; 條件，告訴編譯器該參數所用的暫存器必須與 :&amp;quot;=r&amp;quot;(foo) 所選擇的一致，如此，就能讓編譯器有更多的選擇空間。範例 4.26顯示了我們將前述的內嵌組合語言之條件由 a, b 放寬為 r 之後的結果。&lt;/p&gt;
&lt;p&gt;範例 4.26 將&amp;lt;範例 4.24&amp;gt; 的條件放寬為 “r” – (2)&lt;/p&gt;
&lt;div class=&quot;code&quot;&gt;
&lt;pre&gt;&lt;code&gt;int main(void)                    ;
{                                 ; movl    $10, -4(%ebp)     ; foo=-4(%ebp)=10
  int foo = 10, bar = 15;         ; movl    $15, -8(%ebp)     ; bar=-8(%ebp)=15
                                  ;                           ; 輸入參數：
  asm(                            ; movl    -4(%ebp), %ecx    ; ecx = -4(%ebp)=foo
    &amp;quot;addl %2,%0&amp;quot;                  ; movl    -8(%ebp), %edx    ; edx = -8(%ebp)=bar
    :&amp;quot;=r&amp;quot;(foo)                    ; /APP                      ; 嵌入的程式
    :&amp;quot;0&amp;quot;(foo), &amp;quot;r&amp;quot;(bar)           ; addl %edx,%ecx            ; eax = eax+ebx
    :&amp;quot;0&amp;quot;                          
  );                              ; /NO_APP
  printf(&amp;quot;foo=%d\n&amp;quot;, foo);        ; movl    %ecx, %edx        ; 傳出參數
  return 0;                       ; movl    %edx, %eax        ; foo=eax
}                                 ; movl    %eax, -4(%ebp)
                                  ; movl    -4(%ebp), %eax
                                  ; movl    %eax, 4(%esp)
                                  ; movl    $LC0, (%esp)
                                  ; call    _printf&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;乍看之下，範例 4.26的輸出程式碼並沒有比範例 4.24更短或更有效率，但是，仔細看範例 4.27中兩個組合語言的對照後會發現，foo 變數從 -8(%ebp) 改變為 -4(%ebp)，而 bar 則從 -12(%ebp) 改變為 -8(%ebp)，這是因為在範例 4.26中，由於編譯器選擇改用 addl %edx, %ecx 取代範例 4.24中的 addl %ebx, %eax，這使得範例 4.26的組合語言能少掉第4行的push %ebx 的動作，於是增進了效率，並且減少了堆疊的使用空間。&lt;/p&gt;
&lt;p&gt;範例 4.27 &amp;lt;範例 4.24&amp;gt;與&amp;lt;範例 4.26&amp;gt;的組合語言對照&lt;/p&gt;
&lt;div class=&quot;code&quot;&gt;
&lt;pre&gt;&lt;code&gt;...                               ; ...
_main:                            ;  _main:
    pushl    %ebp                 ;    pushl    %ebp
    movl    %esp, %ebp            ;    movl    %esp, %ebp
    pushl    %ebx                 ;    subl    $24, %esp
    subl    $20, %esp             ;    andl    $-16, %esp
    andl    $-16, %esp            ;    movl    $0, %eax
    movl    $0, %eax              ;    addl    $15, %eax
    addl    $15, %eax             ;    addl    $15, %eax
    addl    $15, %eax             ;    shrl    $4, %eax
    shrl    $4, %eax              ;    sall    $4, %eax
    sall    $4, %eax              ;    movl    %eax, -12(%ebp)
    movl    %eax, -16(%ebp)       ;    movl    -12(%ebp), %eax
    movl    -16(%ebp), %eax       ;    call    __alloca
    call    __alloca              ;    call    ___main
    call    ___main               ;    movl    $10, -4(%ebp)
    movl    $10, -8(%ebp)         ;    movl    $15, -8(%ebp)
    movl    $15, -12(%ebp)        ;    movl    -4(%ebp), %ecx
    movl    -8(%ebp), %eax        ;    movl    -8(%ebp), %edx
    movl    -12(%ebp), %ebx       ;    /APP
/APP                              ;    addl %edx,%ecx
    addl  %ebx,%eax               ;    /NO_APP
/NO_APP                           ;    movl    %ecx, %edx
    movl    %eax, -8(%ebp)        ;    movl    %edx, %eax
    movl    -8(%ebp), %eax        ;    movl    %eax, -4(%ebp)
    movl    %eax, 4(%esp)         ;    movl    -4(%ebp), %eax
    movl    $LC0, (%esp)          ;    movl    %eax, 4(%esp)
    call    _printf               ;    movl    $LC0, (%esp)
    movl    $0, %eax              ;    call    _printf
    movl    -4(%ebp), %ebx        ;    movl    $0, %eax
    leave                         ;    leave
    ret                           ;    ret
...                               ;  ...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;有關gcc 的內嵌組合語言的語法，您可以參考網路上的『GCC Inline Assembly - HOWTO』一文 。&lt;/p&gt;
&lt;p&gt;在本節中，我們已經介紹了如何使用 gcc 進行編譯、組譯與連結的方法，由於gcc是一個編譯、組譯與連結的萬用工具，因此，通常我們不會直接使用 GNU的 as 組譯器，而會改用 gcc 作為組譯器，以便與 C 語言程式進行連結，甚至在C語言當中直接內嵌組合語言，這讓我門不需要完全從組合語言開始撰寫，對系統程式的開發有相當大的用處，特別是嵌入式系統。&lt;/p&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=296763&amp;amp;amp;size=small&amp;amp;amp;timestamp=1786897297&quot; alt=&quot;ccckmit&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=296763)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;ccckmit&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Mon, 11 Oct 2010 07:31:56 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>有時，為了能增進程式的效率，或者在 C 語言當中加入一些組合語言程式碼，我們會採用內嵌的方式，將組合語言內嵌在C語言當中。針對這點，gcc提供了如圖 4.10的內嵌語法，讓我們在 C 語言中可以直接撰寫組合語言。其中，assembler template 為組合語言程式、output operands 為輸入參數、input operands 為輸入參數，而 list of clobbered registers 則指定了被更改的暫存器參數列表。</p> <div class="code"> <pre><code>asm( ; 內嵌起始符號 assembler template ; 組合語言程式 : output operands ; : 輸出參數列表 : input operands ; : 輸入參數列表 : list of clobbered registers ; : 被更改的暫存器列表 ); ; 結束符號</code></pre></div> <p>圖 4.10GNU 的內嵌組合語言語法</p> <p>舉例而言，範例 4.24的C語言程式當中，就內嵌了組合語言。其中，第一欄是內嵌組合語言的C語言程式 inlineAsm1.c，第二欄則是其說明，第三欄是我們利用gcc將該程式轉換成inlineAsm.s 組合語言程式的片段，其中有底線的文字部分對應的是內嵌組合語言的展開部分。</p> <p>在GNU的內嵌組合語言 (assembler template) 中，由於 % 被用作參數 %1, %2, … 的前置字元，因此當遇到暫存器(像是 %eax) 時，必須使用兩個 % 符號 (%%) 作為暫存器的起始標記，因此，在範例 4.24中，原本的 addl %ebx, %eax 指令，就成了 addl %%ebx, %%eax 這個更冗長的指令。</p> <p>在範例 4.24的內嵌參數部分，:&quot;a&quot;(foo), &quot;b&quot;(bar) 是輸入參數，代表要將 foo 變數傳遞給限制條件為 &quot;a&quot; 的暫存器，由於在 IA32 中限制條件為&quot;a&quot;的暫存器就是 eax，因此，foo 變數將會傳給 eax 暫存器。同理，&quot;b&quot;(bar) 參數代表將 bar 傳給 ebx 暫存器。而輸出參數 :&quot;=a&quot;(foo) 則是將 eax 的結果傳回到 foo 變數中。</p> <p>範例 4.24 內嵌組合語言的C程式</p> <div class="code"> <pre><code>int main(void) ; ... { ; movl $10, -8(%ebp) ; foo=-8(%ebp)=10 int foo = 10, bar = 15; ; movl $15, -12(%ebp) ; bar=-12(%ebp)=15 ; 輸入參數： asm( ; movl -8(%ebp), %eax ; eax = -8(%ebp)=foo &quot;addl %%ebx,%%eax&quot; ; movl -12(%ebp), %ebx ; ebx = -12(%ebp)=bar :&quot;=a&quot;(foo) ; /APP ; 嵌入的程式 :&quot;a&quot;(foo), &quot;b&quot;(bar) ; addl %ebx,%eax ; eax = eax+ebx ); ; /NO_APP ; 傳出參數 ; movl %eax, -8(%ebp) ; foo=eax printf(&quot;foo=%d\n&quot;, foo); ; movl -8(%ebp), %eax return 0; ; movl %eax, 4(%esp) } ; movl $LC0, (%esp) ; call _printf ; ...</code></pre></div> <p>請讀者仔細觀察範例 4.24的組合語言程式碼，其中，內嵌指令 asm() 中的輸入參數部分為 :&quot;a&quot;(foo), &quot;b&quot;(bar)。這導致代表foo參數的-8(%ebp)被傳入限制條件 &quot;a&quot; 所對應的 eax暫存器中；而代表bar參數的-12(%ebp)則被傳入限制條件&quot;b&quot;所對應的ebx 暫存器中，然後，才執行內嵌指令 addl %ebx, %eax。在執行完畢之後，輸出參數 :&quot;=a&quot;(foo) 指定將 eax 傳回 foo:-8(%ebp) 變數中，於是最後補上了 movl %eax, -8(%ebp) 指令，完成整個內嵌呼叫的過程。</p> <p>範例 4.25顯示了該程式的編譯執行過程，首先，我們利用 gcc 加上 –S 參數，將C語言編譯為組合語言檔案。接著，再利用gcc作為組譯連結器，將inlineAsm1.s組譯並連結為執行檔，然後執行之，結果，foo果然變成 25，這代表嵌入的組合語言程式發揮了效用。</p> <p>範例 4.25 &lt;範例 4.24&gt; 的編譯與執行過程</p> <div class="code"> <pre><code>$ gcc -S inlineAsm1.c -o inlineAsm1.s ; 將C程式編譯為組合語言 $ gcc inlineAsm1.s -o inlineAsm1 ; 組譯 inlineAsm1.s 組合語言檔 $ ./inlineAsm1 ; 執行inlineAsm1 的執行檔 foo=25 ; 結果： foo+bar 的值為25</code></pre></div> <p>在嵌入式組合語言 asm() 的語法中，每個參數的語法為 &quot;限制條件&quot;(變數)，例如範例 4.24中的 &quot;a&quot;(foo), &quot;b&quot;(bar) 等，其中的 &quot;a&quot;, &quot;b&quot; 都是限制條件，而 (foo), (bar) 則是C語言中所傳入傳出的變數。</p> <p>限制條件可能代表某一個暫存器、一群暫存器、記憶體變數、或者數值等。例如，限制條件m代表『記憶體運算元』、p代表『合法的位址』，而 g 則代表『通用型暫存器、記憶體位址或立即定址的數值』的集合等等。</p> <p>但是，限制條件的設定與CPU的架構有關，同一個符號在不同的CPU中會有不同的意義。例如，在IA32處理器中，限制條件a代表 eax、b 代表 ebx、c代表 ecx、d代表 edx、S 代表 esi、D代表 edi、r代表『eax ebx ecx edx esi edi』的集合、q代表 『eax ebx ecx edx』的集合、g代表『eax,ebx, ecx, edx 或變數』，而 1,則代表與參數 %1 相同, 2 代表與參數 %2 相同 …。</p> 表格 4.1 GNU嵌入式組合語言的限制條件 (針對 IA32處理器)<br /> <table class="wiki-content-table"> <tr> <td>限制</td> <td>說明</td> <td>限制</td> <td>說明</td> </tr> <tr> <td>A</td> <td>eax</td> <td>I</td> <td>(instant constant) 常數 (0到31 之間)</td> </tr> <tr> <td>B</td> <td>ebx</td> <td>m</td> <td>(memory) 記憶體位址</td> </tr> <tr> <td>C</td> <td>ecx</td> <td>r</td> <td>(register) 暫存器eax ebx ecx edx esi edi</td> </tr> <tr> <td>D</td> <td>edx</td> <td>q</td> <td>eax ebx ecx edx</td> </tr> <tr> <td>S</td> <td>esi</td> <td>g</td> <td>(general) eax,ebx, ecx, edx、變數或常數</td> </tr> <tr> <td>D</td> <td>edi</td> <td>0, 1, 2, …</td> <td>參數 %0 %1 %2 &#8230;.</td> </tr> <tr> <td>…</td> <td>…</td> <td>…</td> <td>…</td> </tr> </table> <p>利用表格 4.1中的限制條件，我們可以放寬暫存器的限制，改使用像 addl %2, %0 這樣的方式。這種方式可以讓編譯器自行選擇能使用的暫存器，如此，可以增進程式的效率。在範例 4.26中，我們就使用了此種參數指定的方式，利用 addl %2, %0 指令內嵌，然後，在輸出參數0 中指定 :&quot;=r&quot;(foo)，這使得 foo 可使用的候選的暫存器放寬為 r 條件的『eax ebx ecx edx esi edi』。接著，在輸入參數 %1, %2中指定 :&quot;0&quot;(foo), &quot;r&quot;(bar)，這同樣使得 bar 的候選暫存器放寬為r 條件的『eax ebx ecx edx esi edi』。但是，由於 foo 變數已經在輸出參數 :&quot;=r&quot;(foo)被指定了，因此，必須在第一個輸入參數的 (foo) 前加上 &quot;0&quot; 條件，告訴編譯器該參數所用的暫存器必須與 :&quot;=r&quot;(foo) 所選擇的一致，如此，就能讓編譯器有更多的選擇空間。範例 4.26顯示了我們將前述的內嵌組合語言之條件由 a, b 放寬為 r 之後的結果。</p> <p>範例 4.26 將&lt;範例 4.24&gt; 的條件放寬為 “r” – (2)</p> <div class="code"> <pre><code>int main(void) ; { ; movl $10, -4(%ebp) ; foo=-4(%ebp)=10 int foo = 10, bar = 15; ; movl $15, -8(%ebp) ; bar=-8(%ebp)=15 ; ; 輸入參數： asm( ; movl -4(%ebp), %ecx ; ecx = -4(%ebp)=foo &quot;addl %2,%0&quot; ; movl -8(%ebp), %edx ; edx = -8(%ebp)=bar :&quot;=r&quot;(foo) ; /APP ; 嵌入的程式 :&quot;0&quot;(foo), &quot;r&quot;(bar) ; addl %edx,%ecx ; eax = eax+ebx :&quot;0&quot; ); ; /NO_APP printf(&quot;foo=%d\n&quot;, foo); ; movl %ecx, %edx ; 傳出參數 return 0; ; movl %edx, %eax ; foo=eax } ; movl %eax, -4(%ebp) ; movl -4(%ebp), %eax ; movl %eax, 4(%esp) ; movl $LC0, (%esp) ; call _printf</code></pre></div> <p>乍看之下，範例 4.26的輸出程式碼並沒有比範例 4.24更短或更有效率，但是，仔細看範例 4.27中兩個組合語言的對照後會發現，foo 變數從 -8(%ebp) 改變為 -4(%ebp)，而 bar 則從 -12(%ebp) 改變為 -8(%ebp)，這是因為在範例 4.26中，由於編譯器選擇改用 addl %edx, %ecx 取代範例 4.24中的 addl %ebx, %eax，這使得範例 4.26的組合語言能少掉第4行的push %ebx 的動作，於是增進了效率，並且減少了堆疊的使用空間。</p> <p>範例 4.27 &lt;範例 4.24&gt;與&lt;範例 4.26&gt;的組合語言對照</p> <div class="code"> <pre><code>... ; ... _main: ; _main: pushl %ebp ; pushl %ebp movl %esp, %ebp ; movl %esp, %ebp pushl %ebx ; subl $24, %esp subl $20, %esp ; andl $-16, %esp andl $-16, %esp ; movl $0, %eax movl $0, %eax ; addl $15, %eax addl $15, %eax ; addl $15, %eax addl $15, %eax ; shrl $4, %eax shrl $4, %eax ; sall $4, %eax sall $4, %eax ; movl %eax, -12(%ebp) movl %eax, -16(%ebp) ; movl -12(%ebp), %eax movl -16(%ebp), %eax ; call __alloca call __alloca ; call ___main call ___main ; movl $10, -4(%ebp) movl $10, -8(%ebp) ; movl $15, -8(%ebp) movl $15, -12(%ebp) ; movl -4(%ebp), %ecx movl -8(%ebp), %eax ; movl -8(%ebp), %edx movl -12(%ebp), %ebx ; /APP /APP ; addl %edx,%ecx addl %ebx,%eax ; /NO_APP /NO_APP ; movl %ecx, %edx movl %eax, -8(%ebp) ; movl %edx, %eax movl -8(%ebp), %eax ; movl %eax, -4(%ebp) movl %eax, 4(%esp) ; movl -4(%ebp), %eax movl $LC0, (%esp) ; movl %eax, 4(%esp) call _printf ; movl $LC0, (%esp) movl $0, %eax ; call _printf movl -4(%ebp), %ebx ; movl $0, %eax leave ; leave ret ; ret ... ; ...</code></pre></div> <p>有關gcc 的內嵌組合語言的語法，您可以參考網路上的『GCC Inline Assembly - HOWTO』一文 。</p> <p>在本節中，我們已經介紹了如何使用 gcc 進行編譯、組譯與連結的方法，由於gcc是一個編譯、組譯與連結的萬用工具，因此，通常我們不會直接使用 GNU的 as 組譯器，而會改用 gcc 作為組譯器，以便與 C 語言程式進行連結，甚至在C語言當中直接內嵌組合語言，這讓我門不需要完全從組合語言開始撰寫，對系統程式的開發有相當大的用處，特別是嵌入式系統。</p> <p>by <span class="printuser avatarhover"><a href="http://www.wikidot.com/user:info/ccckmit" ><img class="small" src="http://www.wikidot.com/avatar.php?userid=296763&amp;amp;size=small&amp;amp;timestamp=1786897297" alt="ccckmit" style="background-image:url(http://www.wikidot.com/userkarma.php?u=296763)" /></a><a href="http://www.wikidot.com/user:info/ccckmit" >ccckmit</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://ccckmit.wikidot.com/as:linkc</guid>
				<title>組合語言 -- 模擬 C 語言中的副程式</title>
				<link>http://ccckmit.wikidot.com/as:linkc</link>
				<description>

&lt;div class=&quot;code&quot;&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;

int main() {
    int x = 1;
    int y;
    y = f1(x);
    printf(&amp;quot;y=%d\n&amp;quot;, y);
    return 1;
}
int f1(int t) {
    int b = f2(&amp;amp;t);
    return b+b;
}
int f2(int *p) {
    int r= *p+5;
    return r;
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;如果我們用gcc 編譯器將C 語言轉換為組合語言，就會發現其中有些難以理解的地方，這是因為 gcc 會將程式中的區域變數存放在堆疊當中，並且在進入函數前先將參數壓入堆疊。在進入&lt;/p&gt;
&lt;p&gt;也就是要保存框架指標 ebp 與設定堆疊指標 esp，因此這兩個程式並不能再度呼叫下一層的函數，否則將會導致框架指標遺失，而產生堆疊錯誤的情況。&lt;/p&gt;
&lt;p&gt;在 IA32 的處理器架構下，要進行多層次的副程式呼叫，必須在程式一進入時就保存 ebp 框架指標於堆疊中，然後設定 esp 堆疊指標，接著分配區域變數的空間。當函數呼叫結束，要返回上一層函數時，則必須先將傳回值存入 eax 當中，然後利用 leave 與 ret 等指令，完成返回動作。&lt;/p&gt;
&lt;p&gt;為了觀察上述的過程，我們利用gcc將範例 f2.c 轉換成組合語言 f2.s，以下顯示了這兩個程式的對照情況，只要仔細觀察，您將會瞭解 C 語言函數呼叫機制的實作方式。&lt;/p&gt;
&lt;div class=&quot;code&quot;&gt;
&lt;pre&gt;&lt;code&gt;File:ch03/f2.s                                               ; File:ch03/f2.c
        .file    &amp;quot;f2.c&amp;quot;                                      ; #include &amp;lt;stdio.h&amp;gt;
    .def    ___main;    .scl    2;    .type    32;    .endef ;
    .section .rdata,&amp;quot;dr&amp;quot;                                     ;
LC0:                                                         ;
    .ascii &amp;quot;y=%d\12\0&amp;quot;                                       ;
    .text                                                    ;
.globl _main                                                 ;
    .def    _main;    .scl    2;    .type    32;    .endef   ;
_main:                                                       ; int main() {
    pushl    %ebp                                            ; // 保存框架指標
    movl    %esp, %ebp                                       ; // 設定堆疊指標
    subl    $24, %esp                                        ; // 分配區域變數空間
    andl    $-16, %esp                                       ;
    movl    $0, %eax                                         ;
    addl    $15, %eax                                        ;
    addl    $15, %eax                                        ;
    shrl    $4, %eax                                         ;
    sall    $4, %eax                                         ;
    movl    %eax, -12(%ebp)                                  ;
    movl    -12(%ebp), %eax                                  ;
    call    __alloca                                         ; // 分配堆積(heap)空間
    call    ___main                                          ;
    movl    $1, -4(%ebp)                                     ;     int x = 1;
    movl    -4(%ebp), %eax                                   ;     int y;
    movl    %eax, (%esp)                                     ;
    call    _f1                                              ;     y = f1(x);
    movl    %eax, -8(%ebp)                                   ; // y = eax
    movl    -8(%ebp), %eax                                   ; // eax = y
    movl    %eax, 4(%esp)                                    ; // 參數 y (推入堆疊)
    movl    $LC0, (%esp)                                     ; // 參數 &amp;quot;y=%d\n&amp;quot;
    call    _printf                                          ;     printf(&amp;quot;y=%d\n&amp;quot;, y);
    movl    $1, %eax                                         ; // 設定傳回值 eax=1
    leave                                                    ;
    ret                                                      ;     return 1;
.globl _f1                                                   ; }
    .def    _f1;    .scl    2;    .type    32;    .endef     ;
_f1:                                                         ; int f1(int t) {
    pushl    %ebp                                            ; // 保存框架指標
    movl    %esp, %ebp                                       ; // 設定堆疊指標
    subl    $8, %esp                                         ; // 分配區域變數空間
    leal    8(%ebp), %eax                                    ; // eax = 8(%ebp) 的位址
    movl    %eax, (%esp)                                     ; // esp 上移 8 byte
    call    _f2                                              ;     int b = f2(&amp;amp;t);
    movl    %eax, -4(%ebp)                                   ; // -4(%ebp) 就是 b
    movl    -4(%ebp), %eax                                   ; // eax = b
    addl    -4(%ebp), %eax                                   ; // eax = eax + b
    leave                                                    ;
    ret                                                      ;     return b+b;
.globl _f2                                                   ; }
    .def    _f2;    .scl    2;    .type    32;    .endef     ;
_f2:                                                         ; int f2(int *p) {
    pushl    %ebp                                            ; // 保存框架指標
    movl    %esp, %ebp                                       ; // 設定堆疊指標
    subl    $4, %esp                                         ; // 分配區域變數空間
    movl    8(%ebp), %eax                                    ;
    movl    (%eax), %eax                                     ;
    addl    $5, %eax                                         ;     int r= *p+5;
    movl    %eax, -4(%ebp)                                   ; // 設定傳回值 eax=r
    movl    -4(%ebp), %eax                                   ;
    leave                                                    ;
    ret                                                      ;     return r;
    .def    _f2;    .scl    3;    .type    32;    .endef     ; }
    .def    _printf;    .scl    3;    .type    32;    .endef ;
    .def    _f1;    .scl    3;    .type    32;    .endef     ;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=296763&amp;amp;amp;size=small&amp;amp;amp;timestamp=1786897297&quot; alt=&quot;ccckmit&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=296763)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;ccckmit&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Mon, 11 Oct 2010 07:31:15 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <div class="code"> <pre><code>#include &lt;stdio.h&gt; int main() { int x = 1; int y; y = f1(x); printf(&quot;y=%d\n&quot;, y); return 1; } int f1(int t) { int b = f2(&amp;t); return b+b; } int f2(int *p) { int r= *p+5; return r; }</code></pre></div> <p>如果我們用gcc 編譯器將C 語言轉換為組合語言，就會發現其中有些難以理解的地方，這是因為 gcc 會將程式中的區域變數存放在堆疊當中，並且在進入函數前先將參數壓入堆疊。在進入</p> <p>也就是要保存框架指標 ebp 與設定堆疊指標 esp，因此這兩個程式並不能再度呼叫下一層的函數，否則將會導致框架指標遺失，而產生堆疊錯誤的情況。</p> <p>在 IA32 的處理器架構下，要進行多層次的副程式呼叫，必須在程式一進入時就保存 ebp 框架指標於堆疊中，然後設定 esp 堆疊指標，接著分配區域變數的空間。當函數呼叫結束，要返回上一層函數時，則必須先將傳回值存入 eax 當中，然後利用 leave 與 ret 等指令，完成返回動作。</p> <p>為了觀察上述的過程，我們利用gcc將範例 f2.c 轉換成組合語言 f2.s，以下顯示了這兩個程式的對照情況，只要仔細觀察，您將會瞭解 C 語言函數呼叫機制的實作方式。</p> <div class="code"> <pre><code>File:ch03/f2.s ; File:ch03/f2.c .file &quot;f2.c&quot; ; #include &lt;stdio.h&gt; .def ___main; .scl 2; .type 32; .endef ; .section .rdata,&quot;dr&quot; ; LC0: ; .ascii &quot;y=%d\12\0&quot; ; .text ; .globl _main ; .def _main; .scl 2; .type 32; .endef ; _main: ; int main() { pushl %ebp ; // 保存框架指標 movl %esp, %ebp ; // 設定堆疊指標 subl $24, %esp ; // 分配區域變數空間 andl $-16, %esp ; movl $0, %eax ; addl $15, %eax ; addl $15, %eax ; shrl $4, %eax ; sall $4, %eax ; movl %eax, -12(%ebp) ; movl -12(%ebp), %eax ; call __alloca ; // 分配堆積(heap)空間 call ___main ; movl $1, -4(%ebp) ; int x = 1; movl -4(%ebp), %eax ; int y; movl %eax, (%esp) ; call _f1 ; y = f1(x); movl %eax, -8(%ebp) ; // y = eax movl -8(%ebp), %eax ; // eax = y movl %eax, 4(%esp) ; // 參數 y (推入堆疊) movl $LC0, (%esp) ; // 參數 &quot;y=%d\n&quot; call _printf ; printf(&quot;y=%d\n&quot;, y); movl $1, %eax ; // 設定傳回值 eax=1 leave ; ret ; return 1; .globl _f1 ; } .def _f1; .scl 2; .type 32; .endef ; _f1: ; int f1(int t) { pushl %ebp ; // 保存框架指標 movl %esp, %ebp ; // 設定堆疊指標 subl $8, %esp ; // 分配區域變數空間 leal 8(%ebp), %eax ; // eax = 8(%ebp) 的位址 movl %eax, (%esp) ; // esp 上移 8 byte call _f2 ; int b = f2(&amp;t); movl %eax, -4(%ebp) ; // -4(%ebp) 就是 b movl -4(%ebp), %eax ; // eax = b addl -4(%ebp), %eax ; // eax = eax + b leave ; ret ; return b+b; .globl _f2 ; } .def _f2; .scl 2; .type 32; .endef ; _f2: ; int f2(int *p) { pushl %ebp ; // 保存框架指標 movl %esp, %ebp ; // 設定堆疊指標 subl $4, %esp ; // 分配區域變數空間 movl 8(%ebp), %eax ; movl (%eax), %eax ; addl $5, %eax ; int r= *p+5; movl %eax, -4(%ebp) ; // 設定傳回值 eax=r movl -4(%ebp), %eax ; leave ; ret ; return r; .def _f2; .scl 3; .type 32; .endef ; } .def _printf; .scl 3; .type 32; .endef ; .def _f1; .scl 3; .type 32; .endef ;</code></pre></div> <p>by <span class="printuser avatarhover"><a href="http://www.wikidot.com/user:info/ccckmit" ><img class="small" src="http://www.wikidot.com/avatar.php?userid=296763&amp;amp;size=small&amp;amp;timestamp=1786897297" alt="ccckmit" style="background-image:url(http://www.wikidot.com/userkarma.php?u=296763)" /></a><a href="http://www.wikidot.com/user:info/ccckmit" >ccckmit</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://ccckmit.wikidot.com/as:c2asm</guid>
				<title>組合語言 -- 使用 GNU 工具轉換 C 為組合語言後再修改</title>
				<link>http://ccckmit.wikidot.com/as:c2asm</link>
				<description>

&lt;h1&gt;&lt;span&gt;簡介&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;GNU 的組譯器名稱為 as，該程式屬於 GNU binutil 套件的一部分，在 Linux 與 Cygwin等環境中都有此組譯器，但是，由於保護機制的影響，單純使用 as 組譯器很難在 Cygwin 之下執行。&lt;/p&gt;
&lt;p&gt;實際上，直接使用 as 組譯的情況並不多見，較常見的情況是使用 gcc 作為組譯器，由於 gcc 會在適當的時機呼叫組譯器 as與連結器 ld，因此，使用 GNU工具的程式設計師通常將 gcc 作為編譯、組譯與連結的萬用工具。在本節中，我們也將以 gcc 作為主要的組譯工具。&lt;/p&gt;
&lt;p&gt;為了避免直接撰寫組合語言時誤觸作業系統的保護機制，我們可以利用 gcc 將 C 程式轉換為組合語言，然後再對這些組合語言進行修改，以此種方式『撰寫』組合語言，而非直接從零開始。&lt;/p&gt;
&lt;h1&gt;&lt;span&gt;將C語言編譯為組合語言後修改&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;首先，請讀者先撰寫如範例 4.20的 C語言程式 (swap.c)，該程式宣告了x, y, t等 3 個變數，然後，利用三個指定敘述將 x 與 y 交換，這是一個在排序法中常見的動作。&lt;/p&gt;
&lt;p&gt;範例 4.20 將 x 與 y 交換的C語言程式 (檔名：swap.c)&lt;/p&gt;
&lt;div class=&quot;code&quot;&gt;
&lt;pre&gt;&lt;code&gt;int main() {
  int x=5, y=3, t;
  t=x;
  x=y;
  y=t;
  printf(&amp;quot;x=%d\n&amp;quot;,x);
  printf(&amp;quot;y=%d\n&amp;quot;,y);
  return 1;
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;接著，我們利用 gcc -S swap.c -o swap.s 指令，將C語言程式 (swap.c) 編譯為組合語言檔 (swap.s)，swap.s 組合語言的內容如範例 4.21 (a) 所示。其中，29行的call ___main 指令之前的程式碼，主要是進行堆疊與框架環境的設定動作。接著，30行的movl $5, -4(%ebp) 指令將常數 5 放入變數 -4(%ebp) 這個位址中，該位址即為變數a位於堆疊中的位址。然後，31行的movl $3, -8(%ebp) 指令則是將常數 3 放入變數 b 的位址 -8(%ebp) 中。接著，在32-37 行，執行了 t=x; x=y; y=t 的交換動作，其中的 t 變數位址為 -12(%ebp)。然後，在 38-39 行的兩個指令movl -4(%ebp), %eax; movl %eax, 4(%esp)，將位於 -4(%ebp) 的x變數放到堆疊上，以便作為 printf 函數的第2個參數，然後在 40 行時，再度利用 movl $LC0, (%esp) 指令，將 LC0這個字串 (也就是 &amp;quot;x=%d\12\0&amp;quot; ) 放入堆疊的第一個參數中，然後用 call printf 指令呼叫 printf 函數，這就是輸出指令 printf(&amp;quot;x=%d\n&amp;quot;,x);的呼叫過程。接著，位於42-45 行內的是 printf(&amp;quot;y=%d\n&amp;quot;,y) 的組合語言程式，然後，在 46 行當中，movl $1, %eax 將傳回值 1 放入 eax 暫存器中，然後利用leave; ret兩個指令回到上一層。這就是整個C語言程式 (swap.c) 的 IA32 組合語言。&lt;/p&gt;
&lt;p&gt;範例：指令 gcc -S swap.c -o swap.s 所產生的組合語言 (swap.s)&lt;/p&gt;
&lt;div class=&quot;code&quot;&gt;
&lt;pre&gt;&lt;code&gt;    .file    &amp;quot;swap.c&amp;quot;
    .def ___main; .scl 2; .type    32;    .endef
    .section .rdata,&amp;quot;dr&amp;quot;
LC0:
    .ascii &amp;quot;x=%d\12\0&amp;quot;
LC1:
    .ascii &amp;quot;y=%d\12\0&amp;quot;

    .text
.globl _main
    .def _main; .scl 2; .type 32; .endef
_main:
    pushl    %ebp
    movl    %esp, %ebp
    subl    $24, %esp
    andl    $-16, %esp
    movl    $0, %eax
    addl    $15, %eax
    addl    $15, %eax
    shrl    $4, %eax
    sall    $4, %eax
    movl    %eax, -16(%ebp)
    movl    -16(%ebp), %eax
    call    __alloca
    call    ___main
    movl    $5, -4(%ebp)
    movl    $3, -8(%ebp)
    movl    -4(%ebp), %eax
    movl    %eax, -12(%ebp)
    movl    -8(%ebp), %eax
    movl    %eax, -4(%ebp)
    movl    -12(%ebp), %eax
    movl    %eax, -8(%ebp)
    movl    -4(%ebp), %eax
    movl    %eax, 4(%esp)
    movl    $LC0, (%esp)
    call    _printf
    movl    -8(%ebp), %eax
    movl    %eax, 4(%esp)
    movl    $LC1, (%esp)
    call    _printf
    movl    $1, %eax
    leave
    ret
    .def _printf; .scl 3; .type 32; .endef&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;範例：將 swap.s 組合語言檔修改後儲存為 swap_asm.s&lt;/p&gt;
&lt;div class=&quot;code&quot;&gt;
&lt;pre&gt;&lt;code&gt;    .file    &amp;quot;swap.c&amp;quot;
    .def ___main; .scl 2; .type    32; .endef
    .section .rdata,&amp;quot;dr&amp;quot;
LC0:
    .ascii &amp;quot;x=%d\12\0&amp;quot;
LC1:
    .ascii &amp;quot;y=%d\12\0&amp;quot;
    .data
x:    .long 5
y:    .long 3
t:    .long 0
    .text
.globl _main
    .def _main; .scl 2; .type 32; .endef
_main:
    pushl    %ebp
    movl    %esp, %ebp
    subl    $24, %esp
    andl    $-16, %esp
    movl    $0, %eax
    addl    $15, %eax
    addl    $15, %eax
    shrl    $4, %eax
    sall    $4, %eax
    movl    %eax, -16(%ebp)
    movl    -16(%ebp), %eax
    call    __alloca
    call    ___main

    movl    x, %eax
    movl    %eax, t
    movl    y, %eax
    movl    %eax, x
    movl    t, %eax
    movl    %eax, y
    movl    x, %eax
    movl    %eax, 4(%esp)
    movl    $LC0, (%esp)
    call    _printf
    movl    y, %eax
    movl    %eax, 4(%esp)
    movl    $LC1, (%esp)
    call    _printf
    movl    $1, %eax
    leave
    ret
    .def _printf; .scl 3; .type 32; .endef&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;在讀懂了組合語言程式 (swap.s) 的意義之後，我們就可以修改該組合語言，試著在其中加上一些指令。&lt;/p&gt;
&lt;p&gt;由於C語言編譯器使用堆疊暫存器 esp與框架暫存器 ebp 作為變數的存取點，這對我們來說並不容易理解。因此，筆者將 swap.c 編譯後的組合語言 swap.s 修改為 swap_asm.s，用自己定義的 x, y, t 變數，取代原先的版本。然後，我們再利用 gcc 組譯 swap_asm.s 檔，結果其輸出與 swap.s 一模一樣，這顯示了我們的修改方式是正確的。以下是筆者的編譯與修改過程，讀者也可自行測試看看。&lt;/p&gt;
&lt;p&gt;範例： 將 C 程式 swap.c 編譯為組合語言並修改的過程&lt;/p&gt;
&lt;div class=&quot;code&quot;&gt;
&lt;pre&gt;&lt;code&gt;$ gcc -S swap.c -o swap.s

… 修改 swap.s 為 swap_asm.s

$ gcc swap.s -o swap.o

$ ./swap.o
x=3
y=5

$ gcc swap_asm.s -o swap_asm.o

$ ./swap_asm.o
x=3
y=5&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;從以上的過程，我們可以看到 GNU 組合語言的語法，其中，我們修改的組合語言如範例 4.23所示。其中，我們在資料段 (.data) 中宣告了 x, y, t 等三個變數，並且分別設定初值，而在程式段中，我們利用暫存器 eax 作為中介，移動記憶體變數。例如，t=x 可以由 movl x,%eax與 movl %eax,t 等兩個指令完成。這就是程式的主要部分。接著，我們利用movl x, %eax, movl%eax, 4(%esp) 兩個指令，把 x 變數推入 printf 的參數區，再用 movl $LC0, (%esp) 指令把 &amp;quot;x=%d\n&amp;quot; 字串的指標推入參數區，然後才利用 call _printf指令呼叫 printf 函數。這就是該程式的主要邏輯。&lt;/p&gt;
&lt;p&gt;範例：組合語言檔 swap_asm.s 經過修改的片段&lt;/p&gt;
&lt;div class=&quot;code&quot;&gt;
&lt;pre&gt;&lt;code&gt;    .data
x:    .long 5                  ;   int x = 5, y = 3, t;
y:    .long 3                  ; …
t:    .long 0                  ; 
…                             ; 
    movl    x, %eax            ;   t=x;
    movl    %eax, t            ; 
    movl    y, %eax            ;   x=y;
    movl    %eax, x            ; 
    movl    t, %eax            ;   y=t;
    movl    %eax, y            ; 
    movl    x, %eax            ; 將 x 放入參數區
    movl    %eax, 4(%esp)      ; 
    movl    $LC0, (%esp)       ; 將 &amp;quot;x=%d\n&amp;quot; (LC0) 放入參數區
    call    _printf            ;   printf(&amp;quot;x=%d\n&amp;quot;,x);
    movl    y, %eax            ; 將 y 放入參數區
    movl    %eax, 4(%esp)      ; 
    movl    $LC1, (%esp)       ; 將 &amp;quot;y=%d\n&amp;quot; (LC1) 放入參數區
    call    _printf            ;   printf(&amp;quot;y=%d\n&amp;quot;,y);
…                             ; …&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;透過編譯器產生組合語言的方式，系統程式設計師可以使用如上的修改法，以設計組合語言，而不需要完全從頭開始，這種方法在嵌入式系統的開發過程當中也相當常見，例如，我們可以將效率不好的程式碼修改掉，以增進程式的效率，如此，系統程式人員就能更輕鬆的完成工作，而不需要從頭開始撰寫組合語言。&lt;/p&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=296763&amp;amp;amp;size=small&amp;amp;amp;timestamp=1786897297&quot; alt=&quot;ccckmit&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=296763)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;ccckmit&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Mon, 11 Oct 2010 07:30:31 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <h1><span>簡介</span></h1> <p>GNU 的組譯器名稱為 as，該程式屬於 GNU binutil 套件的一部分，在 Linux 與 Cygwin等環境中都有此組譯器，但是，由於保護機制的影響，單純使用 as 組譯器很難在 Cygwin 之下執行。</p> <p>實際上，直接使用 as 組譯的情況並不多見，較常見的情況是使用 gcc 作為組譯器，由於 gcc 會在適當的時機呼叫組譯器 as與連結器 ld，因此，使用 GNU工具的程式設計師通常將 gcc 作為編譯、組譯與連結的萬用工具。在本節中，我們也將以 gcc 作為主要的組譯工具。</p> <p>為了避免直接撰寫組合語言時誤觸作業系統的保護機制，我們可以利用 gcc 將 C 程式轉換為組合語言，然後再對這些組合語言進行修改，以此種方式『撰寫』組合語言，而非直接從零開始。</p> <h1><span>將C語言編譯為組合語言後修改</span></h1> <p>首先，請讀者先撰寫如範例 4.20的 C語言程式 (swap.c)，該程式宣告了x, y, t等 3 個變數，然後，利用三個指定敘述將 x 與 y 交換，這是一個在排序法中常見的動作。</p> <p>範例 4.20 將 x 與 y 交換的C語言程式 (檔名：swap.c)</p> <div class="code"> <pre><code>int main() { int x=5, y=3, t; t=x; x=y; y=t; printf(&quot;x=%d\n&quot;,x); printf(&quot;y=%d\n&quot;,y); return 1; }</code></pre></div> <p>接著，我們利用 gcc -S swap.c -o swap.s 指令，將C語言程式 (swap.c) 編譯為組合語言檔 (swap.s)，swap.s 組合語言的內容如範例 4.21 (a) 所示。其中，29行的call ___main 指令之前的程式碼，主要是進行堆疊與框架環境的設定動作。接著，30行的movl $5, -4(%ebp) 指令將常數 5 放入變數 -4(%ebp) 這個位址中，該位址即為變數a位於堆疊中的位址。然後，31行的movl $3, -8(%ebp) 指令則是將常數 3 放入變數 b 的位址 -8(%ebp) 中。接著，在32-37 行，執行了 t=x; x=y; y=t 的交換動作，其中的 t 變數位址為 -12(%ebp)。然後，在 38-39 行的兩個指令movl -4(%ebp), %eax; movl %eax, 4(%esp)，將位於 -4(%ebp) 的x變數放到堆疊上，以便作為 printf 函數的第2個參數，然後在 40 行時，再度利用 movl $LC0, (%esp) 指令，將 LC0這個字串 (也就是 &quot;x=%d\12\0&quot; ) 放入堆疊的第一個參數中，然後用 call printf 指令呼叫 printf 函數，這就是輸出指令 printf(&quot;x=%d\n&quot;,x);的呼叫過程。接著，位於42-45 行內的是 printf(&quot;y=%d\n&quot;,y) 的組合語言程式，然後，在 46 行當中，movl $1, %eax 將傳回值 1 放入 eax 暫存器中，然後利用leave; ret兩個指令回到上一層。這就是整個C語言程式 (swap.c) 的 IA32 組合語言。</p> <p>範例：指令 gcc -S swap.c -o swap.s 所產生的組合語言 (swap.s)</p> <div class="code"> <pre><code> .file &quot;swap.c&quot; .def ___main; .scl 2; .type 32; .endef .section .rdata,&quot;dr&quot; LC0: .ascii &quot;x=%d\12\0&quot; LC1: .ascii &quot;y=%d\12\0&quot; .text .globl _main .def _main; .scl 2; .type 32; .endef _main: pushl %ebp movl %esp, %ebp subl $24, %esp andl $-16, %esp movl $0, %eax addl $15, %eax addl $15, %eax shrl $4, %eax sall $4, %eax movl %eax, -16(%ebp) movl -16(%ebp), %eax call __alloca call ___main movl $5, -4(%ebp) movl $3, -8(%ebp) movl -4(%ebp), %eax movl %eax, -12(%ebp) movl -8(%ebp), %eax movl %eax, -4(%ebp) movl -12(%ebp), %eax movl %eax, -8(%ebp) movl -4(%ebp), %eax movl %eax, 4(%esp) movl $LC0, (%esp) call _printf movl -8(%ebp), %eax movl %eax, 4(%esp) movl $LC1, (%esp) call _printf movl $1, %eax leave ret .def _printf; .scl 3; .type 32; .endef</code></pre></div> <p>範例：將 swap.s 組合語言檔修改後儲存為 swap_asm.s</p> <div class="code"> <pre><code> .file &quot;swap.c&quot; .def ___main; .scl 2; .type 32; .endef .section .rdata,&quot;dr&quot; LC0: .ascii &quot;x=%d\12\0&quot; LC1: .ascii &quot;y=%d\12\0&quot; .data x: .long 5 y: .long 3 t: .long 0 .text .globl _main .def _main; .scl 2; .type 32; .endef _main: pushl %ebp movl %esp, %ebp subl $24, %esp andl $-16, %esp movl $0, %eax addl $15, %eax addl $15, %eax shrl $4, %eax sall $4, %eax movl %eax, -16(%ebp) movl -16(%ebp), %eax call __alloca call ___main movl x, %eax movl %eax, t movl y, %eax movl %eax, x movl t, %eax movl %eax, y movl x, %eax movl %eax, 4(%esp) movl $LC0, (%esp) call _printf movl y, %eax movl %eax, 4(%esp) movl $LC1, (%esp) call _printf movl $1, %eax leave ret .def _printf; .scl 3; .type 32; .endef</code></pre></div> <p>在讀懂了組合語言程式 (swap.s) 的意義之後，我們就可以修改該組合語言，試著在其中加上一些指令。</p> <p>由於C語言編譯器使用堆疊暫存器 esp與框架暫存器 ebp 作為變數的存取點，這對我們來說並不容易理解。因此，筆者將 swap.c 編譯後的組合語言 swap.s 修改為 swap_asm.s，用自己定義的 x, y, t 變數，取代原先的版本。然後，我們再利用 gcc 組譯 swap_asm.s 檔，結果其輸出與 swap.s 一模一樣，這顯示了我們的修改方式是正確的。以下是筆者的編譯與修改過程，讀者也可自行測試看看。</p> <p>範例： 將 C 程式 swap.c 編譯為組合語言並修改的過程</p> <div class="code"> <pre><code>$ gcc -S swap.c -o swap.s … 修改 swap.s 為 swap_asm.s $ gcc swap.s -o swap.o $ ./swap.o x=3 y=5 $ gcc swap_asm.s -o swap_asm.o $ ./swap_asm.o x=3 y=5</code></pre></div> <p>從以上的過程，我們可以看到 GNU 組合語言的語法，其中，我們修改的組合語言如範例 4.23所示。其中，我們在資料段 (.data) 中宣告了 x, y, t 等三個變數，並且分別設定初值，而在程式段中，我們利用暫存器 eax 作為中介，移動記憶體變數。例如，t=x 可以由 movl x,%eax與 movl %eax,t 等兩個指令完成。這就是程式的主要部分。接著，我們利用movl x, %eax, movl%eax, 4(%esp) 兩個指令，把 x 變數推入 printf 的參數區，再用 movl $LC0, (%esp) 指令把 &quot;x=%d\n&quot; 字串的指標推入參數區，然後才利用 call _printf指令呼叫 printf 函數。這就是該程式的主要邏輯。</p> <p>範例：組合語言檔 swap_asm.s 經過修改的片段</p> <div class="code"> <pre><code> .data x: .long 5 ; int x = 5, y = 3, t; y: .long 3 ; … t: .long 0 ; … ; movl x, %eax ; t=x; movl %eax, t ; movl y, %eax ; x=y; movl %eax, x ; movl t, %eax ; y=t; movl %eax, y ; movl x, %eax ; 將 x 放入參數區 movl %eax, 4(%esp) ; movl $LC0, (%esp) ; 將 &quot;x=%d\n&quot; (LC0) 放入參數區 call _printf ; printf(&quot;x=%d\n&quot;,x); movl y, %eax ; 將 y 放入參數區 movl %eax, 4(%esp) ; movl $LC1, (%esp) ; 將 &quot;y=%d\n&quot; (LC1) 放入參數區 call _printf ; printf(&quot;y=%d\n&quot;,y); … ; …</code></pre></div> <p>透過編譯器產生組合語言的方式，系統程式設計師可以使用如上的修改法，以設計組合語言，而不需要完全從頭開始，這種方法在嵌入式系統的開發過程當中也相當常見，例如，我們可以將效率不好的程式碼修改掉，以增進程式的效率，如此，系統程式人員就能更輕鬆的完成工作，而不需要從頭開始撰寫組合語言。</p> <p>by <span class="printuser avatarhover"><a href="http://www.wikidot.com/user:info/ccckmit" ><img class="small" src="http://www.wikidot.com/avatar.php?userid=296763&amp;amp;size=small&amp;amp;timestamp=1786897297" alt="ccckmit" style="background-image:url(http://www.wikidot.com/userkarma.php?u=296763)" /></a><a href="http://www.wikidot.com/user:info/ccckmit" >ccckmit</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://ccckmit.wikidot.com/as:gas</guid>
				<title>組合語言 -- GNU 組譯器 (as)</title>
				<link>http://ccckmit.wikidot.com/as:gas</link>
				<description>

&lt;h1&gt;&lt;span&gt;GNU 的組譯報表&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;要讓 GNU 組譯器 as 產生組譯報表，可以利用 -a 參數，其語法為 as -a &amp;lt;asmFile&amp;gt;。以下是一個利用 as 產生組譯報表的範例。&lt;/p&gt;
&lt;div class=&quot;code&quot;&gt;
&lt;pre&gt;&lt;code&gt;C:\ccc\SP\code\ch03&amp;gt;as -a gnu_sum.s

GAS LISTING gnu_sum.s             page 1

   1                      .data
   2 0000 00000000     sum: .long 0
   3 0004 00000000         .text
   3      00000000 
   3      00000000 
   4                  .globl _asmMain
   5                      .def _asmMain; .scl    2; .type 32; .endef
   6                  _asmMain:
   7 0000 B8010000         mov $1, %eax
   7      00
   8                  FOR1:
   9 0005 01050000         addl %eax, sum
   9      0000
  10 000b 83C001           addl $1, %eax
  11 000e 83F80A           cmpl $10,%eax
  12 0011 7EF2             jle FOR1
  13 0013 A1000000         movl sum, %eax
  13      00
  14 0018 C3909090         ret
  14      90909090 
GAS LISTING gnu_sum.s             page 2

DEFINED SYMBOLS
                            *ABS*:00000000 fake
           gnu_sum.s:2      .data:00000000 sum
           gnu_sum.s:6      .text:00000000 _asmMain
           gnu_sum.s:8      .text:00000005 FOR1

NO UNDEFINED SYMBOLS&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;參考文獻&lt;/span&gt;&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;有關 GNU as 組譯器的用法可參考下列網址 &lt;a href=&quot;http://sourceware.org/binutils/docs-2.19/as/&quot;&gt;http://sourceware.org/binutils/docs-2.19/as/&lt;/a&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=296763&amp;amp;amp;size=small&amp;amp;amp;timestamp=1786897297&quot; alt=&quot;ccckmit&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=296763)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;ccckmit&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Mon, 11 Oct 2010 07:24:39 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <h1><span>GNU 的組譯報表</span></h1> <p>要讓 GNU 組譯器 as 產生組譯報表，可以利用 -a 參數，其語法為 as -a &lt;asmFile&gt;。以下是一個利用 as 產生組譯報表的範例。</p> <div class="code"> <pre><code>C:\ccc\SP\code\ch03&gt;as -a gnu_sum.s GAS LISTING gnu_sum.s page 1 1 .data 2 0000 00000000 sum: .long 0 3 0004 00000000 .text 3 00000000 3 00000000 4 .globl _asmMain 5 .def _asmMain; .scl 2; .type 32; .endef 6 _asmMain: 7 0000 B8010000 mov $1, %eax 7 00 8 FOR1: 9 0005 01050000 addl %eax, sum 9 0000 10 000b 83C001 addl $1, %eax 11 000e 83F80A cmpl $10,%eax 12 0011 7EF2 jle FOR1 13 0013 A1000000 movl sum, %eax 13 00 14 0018 C3909090 ret 14 90909090 GAS LISTING gnu_sum.s page 2 DEFINED SYMBOLS *ABS*:00000000 fake gnu_sum.s:2 .data:00000000 sum gnu_sum.s:6 .text:00000000 _asmMain gnu_sum.s:8 .text:00000005 FOR1 NO UNDEFINED SYMBOLS</code></pre></div> <h1><span>參考文獻</span></h1> <ol> <li>有關 GNU as 組譯器的用法可參考下列網址 <a href="http://sourceware.org/binutils/docs-2.19/as/">http://sourceware.org/binutils/docs-2.19/as/</a>。</li> </ol> <p>by <span class="printuser avatarhover"><a href="http://www.wikidot.com/user:info/ccckmit" ><img class="small" src="http://www.wikidot.com/avatar.php?userid=296763&amp;amp;size=small&amp;amp;timestamp=1786897297" alt="ccckmit" style="background-image:url(http://www.wikidot.com/userkarma.php?u=296763)" /></a><a href="http://www.wikidot.com/user:info/ccckmit" >ccckmit</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://ccckmit.wikidot.com/as:windows</guid>
				<title>MS Windows系統下的組合語言</title>
				<link>http://ccckmit.wikidot.com/as:windows</link>
				<description>

&lt;p&gt;您也可以使用組合語言撰寫 MS Windows 的視窗程式，但這並不是一件簡單的事情，也沒有絕對的必要性，因為您可以使用 C/C++ 語言或更高階的 C#, VB 等語言撰寫視窗程式。但是，如果您真的希望學習如何以組合語言撰寫MS Windows 底下的視窗程式，那您可以下載MASM32 這個組譯器並安裝後，就會發現在C:\MASM32資料夾中附有許多進階的組合語言範例，其中包含許多組合語言版的MS Windows視窗程式。範例一就是其中用來顯示對話框的一個範例。其執行畫面如圖一所示。但是，筆者並非 MASM32 的專家，探討這些程式的原理已經超越筆者的能力範圍，在此筆者僅能提供讀者這些基本資訊，詳細的程式設計方式留待有興趣的讀者自行研究。&lt;/p&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=296763&amp;amp;amp;size=small&amp;amp;amp;timestamp=1786897297&quot; alt=&quot;ccckmit&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=296763)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;ccckmit&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Sat, 13 Mar 2010 05:30:07 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>您也可以使用組合語言撰寫 MS Windows 的視窗程式，但這並不是一件簡單的事情，也沒有絕對的必要性，因為您可以使用 C/C++ 語言或更高階的 C#, VB 等語言撰寫視窗程式。但是，如果您真的希望學習如何以組合語言撰寫MS Windows 底下的視窗程式，那您可以下載MASM32 這個組譯器並安裝後，就會發現在C:\MASM32資料夾中附有許多進階的組合語言範例，其中包含許多組合語言版的MS Windows視窗程式。範例一就是其中用來顯示對話框的一個範例。其執行畫面如圖一所示。但是，筆者並非 MASM32 的專家，探討這些程式的原理已經超越筆者的能力範圍，在此筆者僅能提供讀者這些基本資訊，詳細的程式設計方式留待有興趣的讀者自行研究。</p> <p>範例一、以MASM32撰寫組合語言以顯示對話視窗的範例</p> <div class="code"> <pre><code> .486 ; create 32 bit code .model flat, stdcall ; 32 bit memory model option casemap :none ; case sensitive include \masm32\include\dialogs.inc include simple.inc dlgproc PROTO :DWORD,:DWORD,:DWORD,:DWORD .code start: mov hInstance, FUNC(GetModuleHandle,NULL) call main invoke ExitProcess,eax main proc Dialog &quot;Simple Dialog&quot;,&quot;MS Sans Serif&quot;,10, \ ; caption,font,pointsize WS_OVERLAPPED or WS_SYSMENU or DS_CENTER, \ ; style 2, \ ; control count 50,50,150,80, \ ; x y co-ordinates 1024 ; memory buffer size DlgButton &quot;&amp;OK&quot;,WS_TABSTOP,48,40,50,15,IDCANCEL DlgStatic &quot;Simple Dialog Written In MASM32&quot;,SS_CENTER,2,20,140,9,100 CallModalDialog hInstance,0,dlgproc,NULL ret main endp dlgproc proc hWin:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD .if uMsg == WM_INITDIALOG invoke SendMessage,hWin,WM_SETICON,1,FUNC(LoadIcon,NULL,IDI_ASTERISK) .elseif uMsg == WM_COMMAND .if wParam == IDCANCEL jmp quit_dialog .endif .elseif uMsg == WM_CLOSE quit_dialog: invoke EndDialog,hWin,0 .endif xor eax, eax ret dlgproc endp end start</code></pre></div> <div class="image-container aligncenter"><a href="http://ccckmit.wdfiles.com/local--files/as:windows/WindowsAssemblyRun.jpg"><img src="http://ccckmit.wdfiles.com/local--resized-images/as:windows/WindowsAssemblyRun.jpg/medium.jpg" alt="WindowsAssemblyRun.jpg" class="image" /></a></div> <p style="text-align: center;">圖一、&lt;範例一&gt;的執行結果</p> <p>由於許多歷史因素，IBM PC的組合語言程式設計已經變得非常複雜，無法詳細的納入本書的討論範圍。尤其是在 MS Windows 底下的組合語言程式設計，更因為保護模式等機制，而不容易入手。若讀者有興趣，可以嘗試在 MS DOS系統下，設計古老的16位元組合語言，這會有助於理解BIOS與DOS中斷機制等議題。如果您對MS Windows下的組合語言有興趣，則請安裝MASM32的組譯器，參考其中的範例，可以進一步理解使用組合語言撰寫 MS Windows 中視窗程式的方法。</p> <p>對筆者而言，學習MS DOS 或MS Windows下的組合語言顯得較不重要，重要的是要理解組合語言的精神，包含指令集的架構與功能等，以及如何利用組合語言進行記憶體映射輸出入等主題。因此，本書並不嘗試去詳細說明與 MS DOS, Windows 相關的主題，因為這些主題都相當複雜，必須花費許多時間才能入門，特別是針對組合語言的新手而言。</p> <p>by <span class="printuser avatarhover"><a href="http://www.wikidot.com/user:info/ccckmit" ><img class="small" src="http://www.wikidot.com/avatar.php?userid=296763&amp;amp;size=small&amp;amp;timestamp=1786897297" alt="ccckmit" style="background-image:url(http://www.wikidot.com/userkarma.php?u=296763)" /></a><a href="http://www.wikidot.com/user:info/ccckmit" >ccckmit</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://ccckmit.wikidot.com/as:visualstudio</guid>
				<title>在 Visual Studio 中撰寫組合語言</title>
				<link>http://ccckmit.wikidot.com/as:visualstudio</link>
				<description>

&lt;p&gt;在微軟的Visual Studio 中，目前所使用的組譯工具是 ML.exe，ML.exe 除了進行組譯之外，還可以用來進行連結動作。但是，在 Visual Studio 整合環境中，我們並不需要使用指令的方式執行 ML.exe，因為我們可以利用功能表的方式，編譯組合語言程式，然後直接在 Visual Studio 中執行，甚至除錯。&lt;/p&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=296763&amp;amp;amp;size=small&amp;amp;amp;timestamp=1786897297&quot; alt=&quot;ccckmit&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=296763)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;ccckmit&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Sat, 13 Mar 2010 06:31:08 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>在微軟的Visual Studio 中，目前所使用的組譯工具是 ML.exe，ML.exe 除了進行組譯之外，還可以用來進行連結動作。但是，在 Visual Studio 整合環境中，我們並不需要使用指令的方式執行 ML.exe，因為我們可以利用功能表的方式，編譯組合語言程式，然後直接在 Visual Studio 中執行，甚至除錯。</p> <p>要學習如何在 Visual Studio 環境中撰寫組合語言，則可以參考 Kip Irvine 的『Assembly Language for Intel-Based Computers, 5th Edition』一書，以及該書的網站 。在使用 Visual Studio 學習組合語言的開發之前，必須先學習如何設定其開發環境，Kip Irvine在網頁『Getting Started with MASM』 中詳細說明了這些設定方式，請有興趣的初學者仔細研讀。</p> <p>範例一是 Kip Irvine 書籍中的一個範例，該範例會計算eax=0x10000+ 0x40000- 0x20000的結果，然後利用 DumpRegs 印出所有暫存器。該書的範例幾乎都會先以INCLUDE Irvine32.inc指令引用標頭檔，該指令會正確的引用像 DumpRegs 等函數，這讓讀者可以不需要一開始就學習輸出入的方式，降低了組合語言的學習難度。</p> <p>範例一、以 Visual Studio 撰寫MASM組合語言的範例</p> <div class="code"> <pre><code>TITLE Add and Subtract (AddSub.asm) INCLUDE Irvine32.inc .code ; 程式段開始 main PROC ; 主程式 mov eax,10000h ; EAX = 10000h ; 將 0x10000 存入 eax 當中 add eax,40000h ; EAX = 50000h ; 將 0x 40000 加到eax 當中 sub eax,20000h ; EAX = 30000h ; 從 eax 中減去 0x20000 call DumpRegs ; 呼叫 DumpRegs 將所有暫存器印出 exit ; 離開程式 main ENDP END main</code></pre></div> <p>執行結果：</p> <div class="code"> <pre><code> EAX=00030000 EBX=7FFDF000 ECX=0012FFB0 EDX=7C92E514 ESI=00000000 EDI=0B3DF9D4 EBP=0012FFF0 ESP=0012FFC4 EIP=00401024 EFL=00000206 CF=0 SF=0 ZF=0 OF=0 AF=0 PF=1</code></pre></div> <p>讀者可以看到執行後，EAX 的內容為 0x30000，因此，該組合語言正確的執行了 eax=0x10000+ 0x40000- 0x20000的動作。現在，讀者可以在網路上下載該書的範例並執行看看，若您執行 AddSum.asm 這個程式，應可看到如圖一所顯示的執行畫面。</p> <div class="image-container aligncenter"><img src="http://ccckmit.wdfiles.com/local--files/as:visualstudio/VisualStudioAssembly.jpg" alt="VisualStudioAssembly.jpg" class="image" /></div> <p style="text-align: center;">圖一、在Visual Studio 中執行組合語言</p> <div class="image-container aligncenter"><img src="http://ccckmit.wdfiles.com/local--files/as:visualstudio/VisualStudioAssembly.jpg" alt="VisualStudioAssembly.jpg" class="image" /></div> <p style="text-align: center;">圖二、在Visual Studio 中執行 MASM 組合語言的結果</p> <p>另外，在 Irvine.inc 檔案中，也引用了基本的字串函式庫，因此，您可以利用 call WriteString 這個指令，呼叫字串顯示函數，以便將字串輸出到螢幕上。圖三顯示了 main.asm 這個範例於 Visual Studio 中的情況，該程式會將字串 “MASM program example” 字串輸出到螢幕上。在 Irvine 的書籍中，還有許多進階的範例，您可以直接從網路上下載，然後利用 Visual Studio 執行看看，以便觀察組合語言的執行過程，並進一步理解每個指令的意義。</p> <div class="image-container aligncenter"><img src="http://ccckmit.wdfiles.com/local--files/as:visualstudio/VisualStudioAssemblyString.jpg" alt="VisualStudioAssemblyString.jpg" class="image" /></div> <p style="text-align: center;">圖三、用組合語言輸出字串到螢幕上</p> <h1><span>參考文獻</span></h1> <ol> <li>Irvine 組合語言書籍的網址為<a href="http://kipirvine.com/asm/">http://kipirvine.com/asm/</a>，其中書籍的前三章與所有範例程式，可以免費下載。 <ul> <li>Getting Started with MASM, <a href="http://www.kipirvine.com/asm/gettingStarted/index.htm">http://www.kipirvine.com/asm/gettingStarted/index.htm</a></li> </ul> </li> </ol> <p>by <span class="printuser avatarhover"><a href="http://www.wikidot.com/user:info/ccckmit" ><img class="small" src="http://www.wikidot.com/avatar.php?userid=296763&amp;amp;size=small&amp;amp;timestamp=1786897297" alt="ccckmit" style="background-image:url(http://www.wikidot.com/userkarma.php?u=296763)" /></a><a href="http://www.wikidot.com/user:info/ccckmit" >ccckmit</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://ccckmit.wikidot.com/as:masm</guid>
				<title>微軟的組譯器 (MASM)</title>
				<link>http://ccckmit.wikidot.com/as:masm</link>
				<description>

&lt;h1&gt;&lt;span&gt;簡介&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=296763&amp;amp;amp;size=small&amp;amp;amp;timestamp=1786897297&quot; alt=&quot;ccckmit&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=296763)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;ccckmit&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Tue, 13 Oct 2009 06:32:00 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <h1><span>簡介</span></h1> <p>微軟組譯器 MASM 的執行檔在 Visual Studio 2008 當中稱為 ml.exe，您可以啟動 Visual Studio 的命令列工具，然後使用 ml /Fl &lt;asmFile&gt; 的方式進行組譯，並且同時產生出組譯報表檔。以下是我們組譯 sum.asm 的過程，參數中的 /Fl 選項會導致 ml 組譯器將組譯報表輸出到 sum.lst 檔當中，範例 4.19顯示了該組譯報表的內容。報表檔中顯示了各個指令的編碼與位址、變數的位址、區段的長度等等。</p> <div class="code"> <pre><code>C:\ccc\SP\code\ch03&gt;ml /Fl sum.asm Microsoft (R) Macro Assembler Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. Assembling: sum.asm Microsoft (R) Incremental Linker Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved. /OUT:sum.exe sum.obj</code></pre></div> <h1><span>微軟組譯器的報表檔</span></h1> <p>先讓我們將焦點鎖定再以下報表檔中的資料段 (.data)，其中的00000000&#160;00000000 sum DWORD 0 這行代表 sum 變數位於資料段的位址 0之處，而從資料段位址00000004 的兩行中，我們可以看到formatStr BYTE &quot;sum=%d&quot;, 0dh, 0ah, 0 這行指令被組譯為 73&#160;75&#160;6D 3D 25&#160;64&#160;0D 0A 00。</p> <p>若將焦點移向程式段 (.code)，我們會看到 MOV eax, 1 指令被編在程式段的位址0之處，其目的碼為 B8&#160;00000001，而ADD sum, eax 之位址為00000005，其目的碼為01&#160;05&#160;00000000。</p> <p>從報表檔中我們可以清楚的看到 x86 的指令長度是不固定的，像是 ret 0 指令之目的碼為 C3，其長度為 1 bytes，但是CMP eax, 10 指令的目的碼為 83 F8&#160;0A，其長度為 3 bytes，至於ADD sum, eax指令的目的碼為01&#160;05&#160;00000000，其長度達到 6 bytes。</p> <p>範例：add_print.asm</p> <div class="code"> <pre><code>Microsoft (R) Macro Assembler Version 9.00.21022.08 09/08/09 12:12:08 add_print.asm Page 1 - 1 .386 .model flat INCLUDELIB LIBCMT printf PROTO C, format:PTR BYTE, args:VARARG 00000000 .data 00000000 00000000 num DWORD 0 00000004 6E 75 6D 3D 25 formatStr BYTE &quot;num=%d&quot;, 0dh, 0ah, 0 64 0D 0A 00 PUBLIC _main 00000000 .code 00000000 _main PROC 00000000 B8 00000001 MOV eax, 1 00000005 83 C0 04 ADD eax, 4 00000008 83 E8 02 SUB eax, 2 0000000B A3 00000000 R MOV num, eax INVOKE printf, ADDR formatStr, num 00000023 C3 ret 0 00000024 _main ENDP END Microsoft (R) Macro Assembler Version 9.00.21022.08 09/08/09 12:12:08 add_print.asm Symbols 2 - 1 Segments and Groups: N a m e Size Length Align Combine Class FLAT . . . . . . . . . . . . . . GROUP _DATA . . . . . . . . . . . . . 32 Bit 0000000D DWord Public 'DATA' _TEXT . . . . . . . . . . . . . 32 Bit 00000024 DWord Public 'CODE' Procedures, parameters, and locals: N a m e Type Value Attr _main . . . . . . . . . . . . . P Near 00000000 _TEXT Length= 00000024 Public printf . . . . . . . . . . . . . P Near 00000000 FLAT Length= 00000000 External C Symbols: N a m e Type Value Attr @CodeSize . . . . . . . . . . . Number 00000000h @DataSize . . . . . . . . . . . Number 00000000h @Interface . . . . . . . . . . . Number 00000000h @Model . . . . . . . . . . . . . Number 00000007h @code . . . . . . . . . . . . . Text _TEXT @data . . . . . . . . . . . . . Text FLAT @fardata? . . . . . . . . . . . Text FLAT @fardata . . . . . . . . . . . . Text FLAT @stack . . . . . . . . . . . . . Text FLAT formatStr . . . . . . . . . . . Byte 00000004 _DATA num . . . . . . . . . . . . . . DWord 00000000 _DATA 0 Warnings 0 Errors</code></pre></div> <p>範例：sum.asm</p> <div class="code"> <pre><code>Microsoft (R) Macro Assembler Version 9.00.21022.08 09/08/09 12:14:46 sum.asm Page 1 - 1 .386 .model flat INCLUDELIB LIBCMT printf PROTO C, format:PTR BYTE, args:VARARG 00000000 .data 00000000 00000000 sum DWORD 0 00000004 73 75 6D 3D 25 formatStr BYTE &quot;sum=%d&quot;, 0dh, 0ah, 0 64 0D 0A 00 PUBLIC _main 00000000 .code 00000000 _main PROC 00000000 B8 00000001 MOV eax, 1 00000005 FOR1: 00000005 01 05 00000000 R ADD sum, eax 0000000B 83 C0 01 ADD eax, 1 0000000E 83 F8 0A CMP eax, 10 00000011 7E F2 JLE FOR1 INVOKE printf, ADDR formatStr, sum 00000026 C3 ret 0 00000027 _main ENDP END Microsoft (R) Macro Assembler Version 9.00.21022.08 09/08/09 12:14:46 sum.asm Symbols 2 - 1 Segments and Groups: N a m e Size Length Align Combine Class FLAT . . . . . . . . . . . . . . GROUP _DATA . . . . . . . . . . . . . 32 Bit 0000000D DWord Public 'DATA' _TEXT . . . . . . . . . . . . . 32 Bit 00000027 DWord Public 'CODE' Procedures, parameters, and locals: N a m e Type Value Attr _main . . . . . . . . . . . . . P Near 00000000 _TEXT Length= 00000027 Public FOR1 . . . . . . . . . . . . . L Near 00000005 _TEXT printf . . . . . . . . . . . . . P Near 00000000 FLAT Length= 00000000 External C Symbols: N a m e Type Value Attr @CodeSize . . . . . . . . . . . Number 00000000h @DataSize . . . . . . . . . . . Number 00000000h @Interface . . . . . . . . . . . Number 00000000h @Model . . . . . . . . . . . . . Number 00000007h @code . . . . . . . . . . . . . Text _TEXT @data . . . . . . . . . . . . . Text FLAT @fardata? . . . . . . . . . . . Text FLAT @fardata . . . . . . . . . . . . Text FLAT @stack . . . . . . . . . . . . . Text FLAT formatStr . . . . . . . . . . . Byte 00000004 _DATA sum . . . . . . . . . . . . . . DWord 00000000 _DATA 0 Warnings 0 Errors</code></pre></div> <p>另外，範例 4.19的報表檔中也顯示了符號表的內容，像是 FOR1標記的位址為 _TEXT 段的 00000005，formatStr 變數的位址為 _DATA 段的 00000004，而 sum 的位址則為 _DATA 段的 00000000 等等。仔細觀察這些報表檔，您將會更瞭解組譯器的設計原理，以及 x86 的指令集架構。</p> <p>by <span class="printuser avatarhover"><a href="http://www.wikidot.com/user:info/ccckmit" ><img class="small" src="http://www.wikidot.com/avatar.php?userid=296763&amp;amp;size=small&amp;amp;timestamp=1786897297" alt="ccckmit" style="background-image:url(http://www.wikidot.com/userkarma.php?u=296763)" /></a><a href="http://www.wikidot.com/user:info/ccckmit" >ccckmit</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://ccckmit.wikidot.com/as:boot</guid>
				<title>個人電腦 (x86) 的最小啟動程式</title>
				<link>http://ccckmit.wikidot.com/as:boot</link>
				<description>

&lt;h1&gt;&lt;span&gt;簡介&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;在本文中，我們將示範如何撰寫一個小型的 IBM PC (x86) 啟動程式。但或許稱這個程式為啟動程式有點太過頭了，其實我們只是要寫一個開機時可以印出 “Hello, Booter!” 訊息的程式罷了。&lt;/p&gt;
&lt;p&gt;在PC一開機時，BIOS中就具有一個小型的啟動程式 (第一層啟動程式)，該啟動程式會根據CMOS的開機設定，嘗試載入光碟、軟碟或硬碟的啟動磁區，然後載入該磁區並執行其中的程式，這個啟動磁區中的程式就是PC的第二層啟動程式。&lt;/p&gt;
&lt;p&gt;通常，這個啟動磁區的程式會進一步載入作業系統，像是 DOS、MS. Windows或 Linux。但是，在本節中，我們並不嘗試載入作業系統，只是單純的於啟動後，在螢幕上印出 “Hello, Booter !” 的訊息而已。&lt;/p&gt;
&lt;h1&gt;&lt;span&gt;啟動程式的組合語言&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;現在，就讓我們來撰寫一個簡單的PC啟動程式，如範例 1 所示，該程式的來源為楊文博的《使用開源軟體-自己動手寫作業系統》 一書的第二章，該書有免費的電子版，您可於網路上直接下載。&lt;/p&gt;
&lt;p&gt;範例 1. 個人電腦 PC 的小型啟動程式 (檔案名稱： boot.s)&lt;/p&gt;
&lt;div class=&quot;code&quot;&gt;
&lt;pre&gt;&lt;code&gt;.code16                 #使用16位元模式彙編
.text                   #程式碼片段開始
    mov %cs,%ax
    mov %ax,%ds
    mov %ax,%es
    call DispStr        #調用顯示字串常式
    jmp .               #無限迴圈
DispStr:
    mov $msg, %ax
    mov %ax,%bp         #ES:BP = 串地址
    mov $16,%cx         #CX = 串長度
    mov $0x1301,%ax     #AH = 13, AL = 01h
    mov $0x00c,%bx      #頁號為0(BH = 0) 黑底紅字(BL = 0Ch,高亮)
    mov $0,%dl
    int $0x10           #10h 號中斷
    ret
msg:.ascii &amp;quot;Hello, Booter !&amp;quot;
.org 510                #填充到~510~位元組處
.word 0xaa55            #結束標誌&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;啟動程式的連結檔&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;要讓這個啟動程式執行，必須使用連結檔，將程式連結到 PC的啟動位址 0x7C00上，然後定義啟動位址的符號 (在 Cygwin 中的啟動符號為 c，但在Linux 中的啟動符號為 _ftext)，範例 2 顯示了該啟動程式的連結檔 boot.ld，由於筆者是在 Cygwin底下操作的，因此，啟動符號設定為 c。&lt;/p&gt;
&lt;p&gt;範例 2 啟動程式的連結檔(Link Script) (檔案名稱： boot.ld)&lt;/p&gt;
&lt;div class=&quot;code&quot;&gt;
&lt;pre&gt;&lt;code&gt;SECTIONS
{
    .text 0x7c00 : 
    {
        c = .; /* Program will be loaded to 0x7c00. */
    } = 0
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;&lt;span&gt;啟動程式的專案檔&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;接著，我們必須撰寫專案檔，以便進行編譯、連結等工作，範例 6.27顯示了該啟動程式的專案檔 (Makefile)，讀者可以利用 make 指令，重建該啟動程式專案。&lt;/p&gt;
&lt;p&gt;範例 3 啟動程式的專案檔 (Makefile) (檔案名稱： Makefile)&lt;/p&gt;
&lt;div class=&quot;code&quot;&gt;
&lt;pre&gt;&lt;code&gt;CC=gcc
LD=ld
# 使用連接腳本 boot.ld
LDFILE=boot.ld 
OBJCOPY=objcopy

all: boot.img

# Step 1: 使用 gcc 將 boot.S 編譯成目的檔 boot.o
boot.o: boot.S
    $(CC) -c boot.S

# Step 2: 使用ld 連接腳本 boot.ld 將 boot.o 連接成可執行檔 boot.elf
boot.elf: boot.o
    $(LD) boot.o -o boot.elf -e c -T$(LDFILE)

# Step 3: 使用 objcopy 移除 boot.elf 中沒有用的 段(.comment,.note,...),
#         並且去掉所有符號資訊，輸出為二進位檔案 boot.bin 。
boot.bin : boot.elf
    @$(OBJCOPY) -R .pdr -R .comment -R.note -S -O binary boot.elf boot.bin

 # Step 4: 生成可啟動軟碟鏡像。
boot.img: boot.bin
    @dd if=boot.bin of=boot.img bs=512 count=1 
    # 呼叫 boot.bin 生成鏡像檔第一個磁區，
    # 並在 bin 生成的鏡像檔後補上空白，最後成為合適大小的軟碟鏡像
    @dd if=/dev/zero of=boot.img skip=1 seek=1 bs=512 count=2879

clean:
    @rm -rf boot.o boot.elf boot.bin boot.img&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;您可以使用 make 指令建置該專案，範例 6.28是我們在 Cygwin 環境中建置該啟動程式的過程，建置完成後，會有一個大小為 1.44MB 的檔案 boot.img產生。&lt;/p&gt;
&lt;h1&gt;&lt;span&gt;使用 VirtualPC 執行該啟動程式&lt;/span&gt;&lt;/h1&gt;
&lt;p&gt;範例 4. IBM PC 啟動程式的建置過程 (在 Cygwin 中建置 IBM PC 的啟動程式)&lt;/p&gt;
&lt;div class=&quot;code&quot;&gt;
&lt;pre&gt;&lt;code&gt;ccc@ccc-kmit2 ~/boot
$ make clean

ccc@ccc-kmit2 ~/boot
$ ls
Makefileboot.ldboot.s

ccc@ccc-kmit2 ~/boot
$ make
gcc -c boot.S
ld boot.o -o boot.elf -e c -Tboot.ld
1+0 records in
1+0 records out
512 bytes (512 B) copied, 0 s, Infinity B/s
# 在 bin 生成的鏡像檔後補上空白，最後成為合適大小的軟碟鏡像
2879+0 records in
2879+0 records out
1474048 bytes (1.5 MB) copied, 0.085 s, 17.3 MB/s

ccc@ccc-kmit2 ~/boot
$ ls -all
total 1455
drwxrwxrwx+  2 ccc None       0 May 28 14:42 .
drwxrwxrwx+ 11 ccc None       0 May 28 12:02 ..
-rwxrwxrwx   1 ccc None     866 Apr 28 13:07 Makefile
-rwxr-xr-x   1 ccc None     512 May 28 14:42 boot.bin
-rwxr-xr-x   1 ccc None    1890 May 28 14:42 boot.elf
-rw-r--r--   1 ccc None 1474560 May 28 14:42 boot.img
-rwxrwxrwx   1 ccc None      96 May 28 11:19 boot.ld
-rw-r--r--   1 ccc None     858 May 28 14:42 boot.o
-rwxrwxrwx   1 ccc None     453 May 28 11:21 boot.s&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;您也可以將此映像檔轉錄到1.44MB的軟碟片當中，然後重新啟動電腦 (請注意必須於開機後設定成以軟碟機啟動的開機順序)，就會看到電腦上出現紅色的 Hello, Booter ! 字樣。&lt;/p&gt;
&lt;p&gt;但是，現在許多PC都已經沒有軟碟機了，因此，較為通用的方法是使用像是 VMWare、VirtualPC、VirtualBox 等虛擬機器，然後，用這個檔案就可以作為軟碟映像檔，將其作為虛擬的軟碟機使用。&lt;/p&gt;
&lt;p&gt;當您在 Virtual PC 中建立了一個新的虛擬機器之後，就可以啟動該虛擬機器，然後按下『Floppy/Capture Floppy Disk Image…』的功能，接著選取方才所產生的 boot.img 檔作為虛擬軟碟片 (如圖 2 所示)，然後，按下『開始』按鈕，您就會看到如圖 3 所示的執行結果，在螢幕上出現 “Hello, Booter !” 的紅色字樣。這便是範例 1 的執行結果。&lt;/p&gt;
&lt;div class=&quot;image-container aligncenter&quot;&gt;&lt;img src=&quot;http://ccckmit.wdfiles.com/local--files/as:boot/VirtualPCBootDisk.jpg&quot; alt=&quot;VirtualPCBootDisk.jpg&quot; class=&quot;image&quot; /&gt;&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;圖 2. 在 Virtual PC 中設定 boot.img 為虛擬軟碟機的畫面&lt;/p&gt;
&lt;div class=&quot;image-container aligncenter&quot;&gt;&lt;img src=&quot;http://ccckmit.wdfiles.com/local--files/as:boot/VirtualPCBootRun.jpg&quot; alt=&quot;VirtualPCBootRun.jpg&quot; class=&quot;image&quot; /&gt;&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;圖 3. 映像檔 boot.img 在 Virtual PC 中的執行結果&lt;/p&gt;
&lt;h1&gt;&lt;span&gt;參考文獻&lt;/span&gt;&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;《使用開源軟體-自己動手寫作業系統》可於 &lt;a href=&quot;http://share.solrex.cn/WriteOS/download.php&quot;&gt;http://share.solrex.cn/WriteOS/download.php&lt;/a&gt; 網頁下載 (楊文博著)，該書乃是參考《自己動手寫作業系統》（於淵著）所寫的開放原始碼書籍。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=296763&amp;amp;amp;size=small&amp;amp;amp;timestamp=1786897297&quot; alt=&quot;ccckmit&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=296763)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;ccckmit&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Thu, 14 Jan 2010 06:43:33 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <h1><span>簡介</span></h1> <p>在本文中，我們將示範如何撰寫一個小型的 IBM PC (x86) 啟動程式。但或許稱這個程式為啟動程式有點太過頭了，其實我們只是要寫一個開機時可以印出 “Hello, Booter!” 訊息的程式罷了。</p> <p>在PC一開機時，BIOS中就具有一個小型的啟動程式 (第一層啟動程式)，該啟動程式會根據CMOS的開機設定，嘗試載入光碟、軟碟或硬碟的啟動磁區，然後載入該磁區並執行其中的程式，這個啟動磁區中的程式就是PC的第二層啟動程式。</p> <p>通常，這個啟動磁區的程式會進一步載入作業系統，像是 DOS、MS. Windows或 Linux。但是，在本節中，我們並不嘗試載入作業系統，只是單純的於啟動後，在螢幕上印出 “Hello, Booter !” 的訊息而已。</p> <h1><span>啟動程式的組合語言</span></h1> <p>現在，就讓我們來撰寫一個簡單的PC啟動程式，如範例 1 所示，該程式的來源為楊文博的《使用開源軟體-自己動手寫作業系統》 一書的第二章，該書有免費的電子版，您可於網路上直接下載。</p> <p>範例 1. 個人電腦 PC 的小型啟動程式 (檔案名稱： boot.s)</p> <div class="code"> <pre><code>.code16 #使用16位元模式彙編 .text #程式碼片段開始 mov %cs,%ax mov %ax,%ds mov %ax,%es call DispStr #調用顯示字串常式 jmp . #無限迴圈 DispStr: mov $msg, %ax mov %ax,%bp #ES:BP = 串地址 mov $16,%cx #CX = 串長度 mov $0x1301,%ax #AH = 13, AL = 01h mov $0x00c,%bx #頁號為0(BH = 0) 黑底紅字(BL = 0Ch,高亮) mov $0,%dl int $0x10 #10h 號中斷 ret msg:.ascii &quot;Hello, Booter !&quot; .org 510 #填充到~510~位元組處 .word 0xaa55 #結束標誌</code></pre></div> <h1><span>啟動程式的連結檔</span></h1> <p>要讓這個啟動程式執行，必須使用連結檔，將程式連結到 PC的啟動位址 0x7C00上，然後定義啟動位址的符號 (在 Cygwin 中的啟動符號為 c，但在Linux 中的啟動符號為 _ftext)，範例 2 顯示了該啟動程式的連結檔 boot.ld，由於筆者是在 Cygwin底下操作的，因此，啟動符號設定為 c。</p> <p>範例 2 啟動程式的連結檔(Link Script) (檔案名稱： boot.ld)</p> <div class="code"> <pre><code>SECTIONS { .text 0x7c00 : { c = .; /* Program will be loaded to 0x7c00. */ } = 0 }</code></pre></div> <h1><span>啟動程式的專案檔</span></h1> <p>接著，我們必須撰寫專案檔，以便進行編譯、連結等工作，範例 6.27顯示了該啟動程式的專案檔 (Makefile)，讀者可以利用 make 指令，重建該啟動程式專案。</p> <p>範例 3 啟動程式的專案檔 (Makefile) (檔案名稱： Makefile)</p> <div class="code"> <pre><code>CC=gcc LD=ld # 使用連接腳本 boot.ld LDFILE=boot.ld OBJCOPY=objcopy all: boot.img # Step 1: 使用 gcc 將 boot.S 編譯成目的檔 boot.o boot.o: boot.S $(CC) -c boot.S # Step 2: 使用ld 連接腳本 boot.ld 將 boot.o 連接成可執行檔 boot.elf boot.elf: boot.o $(LD) boot.o -o boot.elf -e c -T$(LDFILE) # Step 3: 使用 objcopy 移除 boot.elf 中沒有用的 段(.comment,.note,...), # 並且去掉所有符號資訊，輸出為二進位檔案 boot.bin 。 boot.bin : boot.elf @$(OBJCOPY) -R .pdr -R .comment -R.note -S -O binary boot.elf boot.bin # Step 4: 生成可啟動軟碟鏡像。 boot.img: boot.bin @dd if=boot.bin of=boot.img bs=512 count=1 # 呼叫 boot.bin 生成鏡像檔第一個磁區， # 並在 bin 生成的鏡像檔後補上空白，最後成為合適大小的軟碟鏡像 @dd if=/dev/zero of=boot.img skip=1 seek=1 bs=512 count=2879 clean: @rm -rf boot.o boot.elf boot.bin boot.img</code></pre></div> <p>您可以使用 make 指令建置該專案，範例 6.28是我們在 Cygwin 環境中建置該啟動程式的過程，建置完成後，會有一個大小為 1.44MB 的檔案 boot.img產生。</p> <h1><span>使用 VirtualPC 執行該啟動程式</span></h1> <p>範例 4. IBM PC 啟動程式的建置過程 (在 Cygwin 中建置 IBM PC 的啟動程式)</p> <div class="code"> <pre><code>ccc@ccc-kmit2 ~/boot $ make clean ccc@ccc-kmit2 ~/boot $ ls Makefileboot.ldboot.s ccc@ccc-kmit2 ~/boot $ make gcc -c boot.S ld boot.o -o boot.elf -e c -Tboot.ld 1+0 records in 1+0 records out 512 bytes (512 B) copied, 0 s, Infinity B/s # 在 bin 生成的鏡像檔後補上空白，最後成為合適大小的軟碟鏡像 2879+0 records in 2879+0 records out 1474048 bytes (1.5 MB) copied, 0.085 s, 17.3 MB/s ccc@ccc-kmit2 ~/boot $ ls -all total 1455 drwxrwxrwx+ 2 ccc None 0 May 28 14:42 . drwxrwxrwx+ 11 ccc None 0 May 28 12:02 .. -rwxrwxrwx 1 ccc None 866 Apr 28 13:07 Makefile -rwxr-xr-x 1 ccc None 512 May 28 14:42 boot.bin -rwxr-xr-x 1 ccc None 1890 May 28 14:42 boot.elf -rw-r--r-- 1 ccc None 1474560 May 28 14:42 boot.img -rwxrwxrwx 1 ccc None 96 May 28 11:19 boot.ld -rw-r--r-- 1 ccc None 858 May 28 14:42 boot.o -rwxrwxrwx 1 ccc None 453 May 28 11:21 boot.s</code></pre></div> <p>您也可以將此映像檔轉錄到1.44MB的軟碟片當中，然後重新啟動電腦 (請注意必須於開機後設定成以軟碟機啟動的開機順序)，就會看到電腦上出現紅色的 Hello, Booter ! 字樣。</p> <p>但是，現在許多PC都已經沒有軟碟機了，因此，較為通用的方法是使用像是 VMWare、VirtualPC、VirtualBox 等虛擬機器，然後，用這個檔案就可以作為軟碟映像檔，將其作為虛擬的軟碟機使用。</p> <p>當您在 Virtual PC 中建立了一個新的虛擬機器之後，就可以啟動該虛擬機器，然後按下『Floppy/Capture Floppy Disk Image…』的功能，接著選取方才所產生的 boot.img 檔作為虛擬軟碟片 (如圖 2 所示)，然後，按下『開始』按鈕，您就會看到如圖 3 所示的執行結果，在螢幕上出現 “Hello, Booter !” 的紅色字樣。這便是範例 1 的執行結果。</p> <div class="image-container aligncenter"><img src="http://ccckmit.wdfiles.com/local--files/as:boot/VirtualPCBootDisk.jpg" alt="VirtualPCBootDisk.jpg" class="image" /></div> <p style="text-align: center;">圖 2. 在 Virtual PC 中設定 boot.img 為虛擬軟碟機的畫面</p> <div class="image-container aligncenter"><img src="http://ccckmit.wdfiles.com/local--files/as:boot/VirtualPCBootRun.jpg" alt="VirtualPCBootRun.jpg" class="image" /></div> <p style="text-align: center;">圖 3. 映像檔 boot.img 在 Virtual PC 中的執行結果</p> <h1><span>參考文獻</span></h1> <ol> <li>《使用開源軟體-自己動手寫作業系統》可於 <a href="http://share.solrex.cn/WriteOS/download.php">http://share.solrex.cn/WriteOS/download.php</a> 網頁下載 (楊文博著)，該書乃是參考《自己動手寫作業系統》（於淵著）所寫的開放原始碼書籍。</li> </ol> <p>by <span class="printuser avatarhover"><a href="http://www.wikidot.com/user:info/ccckmit" ><img class="small" src="http://www.wikidot.com/avatar.php?userid=296763&amp;amp;size=small&amp;amp;timestamp=1786897297" alt="ccckmit" style="background-image:url(http://www.wikidot.com/userkarma.php?u=296763)" /></a><a href="http://www.wikidot.com/user:info/ccckmit" >ccckmit</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://ccckmit.wikidot.com/as:dos</guid>
				<title>MS DOS系統中的組合語言</title>
				<link>http://ccckmit.wikidot.com/as:dos</link>
				<description>

&lt;p&gt;目前，學習組合語言時，仍有許多課程以MS DOS 系統為主，因為 MS DOS 系統的組合語言較為簡單，而且學習者可以任意操控系統，不會受到保護模式的限制。&lt;/p&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=296763&amp;amp;amp;size=small&amp;amp;amp;timestamp=1786897297&quot; alt=&quot;ccckmit&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=296763)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;ccckmit&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Sat, 13 Mar 2010 05:19:49 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>目前，學習組合語言時，仍有許多課程以MS DOS 系統為主，因為 MS DOS 系統的組合語言較為簡單，而且學習者可以任意操控系統，不會受到保護模式的限制。</p> <p>在表格一的PC的中斷表中，第21號中斷是保留給 MS DOS 使用的，因此，當您在 DOS 下撰寫組合語言時，通常會一直的呼叫21號中斷，以進行DOS的系統呼叫。表格 3.4顯示了部分的 DOS 中斷表。</p> 表格一、DOS的中斷表<br /> <table class="wiki-content-table"> <tr> <td>AH</td> <td>說明</td> <td>AH</td> <td>說明</td> </tr> <tr> <td>0</td> <td>讀取字元，回傳 AL=字元</td> <td>2A</td> <td>取得系統日期</td> </tr> <tr> <td>1</td> <td>輸出字元，參數DL=字元</td> <td>2B</td> <td>設定系統日期</td> </tr> <tr> <td>2</td> <td>從序列埠讀取字元</td> <td>…</td> <td></td> </tr> <tr> <td>3</td> <td>寫出字元道序列埠</td> <td>4B</td> <td>載入或執行程式</td> </tr> <tr> <td>4</td> <td>將字元寫到印表機</td> <td>4C</td> <td>終止行程</td> </tr> <tr> <td>…</td> <td>…</td> <td></td> <td></td> </tr> <tr> <td>9</td> <td>將字串寫入標準輸出 DS:DX = 字串的位址</td> <td>7305h</td> <td>絕對磁碟的讀取與寫入</td> </tr> </table> <p>如果您安裝了 MS DOS 系統，就可以透過 int 21h中斷與 MS DOS 溝通，範例 3.17顯示了一個在 DOS 中使用 int 21h 中的 ah=9 號服務印出字串的方法。</p> <p>範例一、利用DOS系統呼叫進行輸出入</p> <p>組合語言 (Intel 語法)</p> <div class="code"> <pre><code>code segment ; start 段開始位址 assume cs:code,ds:code ; 設定程式段及資料段 org 100h ; 起始位址 start: jmp begin ; 程式進入點 msg db 'Hello!$' ; 要印出的訊息 begin: mov dx,offset msg ; 設定參數 ds:dx = 字串起點 mov ah,9 ; 設定9號服務 int 21h ; 進行DOS系統呼叫 mov ax,4c00h ; 設定4C號服務 int 21h ; 進行DOS系統呼叫 code ends ; .code 段結束 end ; 程式結束點</code></pre></div> <p>by <span class="printuser avatarhover"><a href="http://www.wikidot.com/user:info/ccckmit" ><img class="small" src="http://www.wikidot.com/avatar.php?userid=296763&amp;amp;size=small&amp;amp;timestamp=1786897297" alt="ccckmit" style="background-image:url(http://www.wikidot.com/userkarma.php?u=296763)" /></a><a href="http://www.wikidot.com/user:info/ccckmit" >ccckmit</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://ccckmit.wikidot.com/as:bios</guid>
				<title>BIOS 與組合語言 (IBM PC)</title>
				<link>http://ccckmit.wikidot.com/as:bios</link>
				<description>

&lt;p&gt;IBM PC個人電腦 （以下簡PC） 目前使用的是IA32 的處理器，其啟動程式燒錄在 BIOS 當中。當PC啟動時，會進入 BIOS的啟動程式中，BIOS會進行『系統組態的分析』（System Configuration Analysis），以分析CPU型號、記憶體大小、軟、硬碟機的數量與型式、是否安裝浮點運算器等，做為其它動作的重要參考資料。接著進行『開機自我測試』（POST，Power-On Self Test），以測試記憶體、晶片組、CMOS儲存資料、鍵盤和磁碟機等硬體，若有錯則以訊息告知所在。 接著，會載入作業系統，像是 MS.MS DOS, MS.MS Windows, Linux 等。&lt;/p&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=296763&amp;amp;amp;size=small&amp;amp;amp;timestamp=1786897297&quot; alt=&quot;ccckmit&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=296763)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;ccckmit&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Fri, 12 Mar 2010 09:22:33 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>IBM PC個人電腦 （以下簡PC） 目前使用的是IA32 的處理器，其啟動程式燒錄在 BIOS 當中。當PC啟動時，會進入 BIOS的啟動程式中，BIOS會進行『系統組態的分析』（System Configuration Analysis），以分析CPU型號、記憶體大小、軟、硬碟機的數量與型式、是否安裝浮點運算器等，做為其它動作的重要參考資料。接著進行『開機自我測試』（POST，Power-On Self Test），以測試記憶體、晶片組、CMOS儲存資料、鍵盤和磁碟機等硬體，若有錯則以訊息告知所在。 接著，會載入作業系統，像是 MS.MS DOS, MS.MS Windows, Linux 等。</p> <p>另外，BIOS當中燒錄有中斷向量與中斷程式，因此、許多的輸出入動作都可以透過呼叫BIOS完成，不需要程式設計人員再撰寫輸出入程式。這對系統的開發人員而言，是較為方便的，但是對學習IA32組合語言的人而言，往往會將BIOS視為一組神奇的函數，反而無法理解輸出入的原理。</p> <p>PC的BIOS模組，是由中斷向量 (0x000-0x400)、中斷資料區 (0x400-0x470) 與中斷處理函數所形成的，因此，使用像int $0x10 這樣的指令，就可以呼叫第 10 號中斷，在螢幕上輸出字串。這樣的指令其實是讓程式透過中斷向量，跳入中斷處理函數中，真正的輸出入反而是在中斷處理函數中做完了。</p> <p>BIOS的資料區包含了輸出入的資訊，舉例而言，位移0x1E-0x3D之處存放了鍵盤緩衝區 (Keyboard typeahead buffer)，其中存放有一連串的鍵盤掃描碼，等待16號中斷 (int 16h) 進行處理。表格 1 顯示了PC的BIOS資料區中，各記憶體位址所包含的資料。</p> 表格 1. 個人電腦的BIOS資料區<br /> <table class="wiki-content-table"> <tr> <td>位移</td> <td>說明</td> <td>位移</td> <td>說明</td> </tr> <tr> <td>0000-0007</td> <td>COM1-COM4埠位址</td> <td>004A-004B</td> <td>螢幕的欄數</td> </tr> <tr> <td>0008-000F</td> <td>LPT1-LPT4埠位址</td> <td>004C-004D</td> <td>視訊緩衝區的長度</td> </tr> <tr> <td>0010-0011</td> <td>已安裝的硬體清單</td> <td>004E-004F</td> <td>視訊緩衝區的起點</td> </tr> <tr> <td>0012</td> <td>初始化旗標</td> <td>0050-005F</td> <td>游標位址 (8個視訊頁)</td> </tr> <tr> <td>0013-0014</td> <td>記憶體的大小(KB)</td> <td>0060</td> <td>游標結束列</td> </tr> <tr> <td>0015-0016</td> <td>I/O通道的記憶體</td> <td>0061</td> <td>游標起始列</td> </tr> <tr> <td>0017-0018</td> <td>鍵盤的狀態旗標</td> <td>0062</td> <td>目前顯示的視訊頁編號</td> </tr> <tr> <td>0019</td> <td>替代鍵的儲存區</td> <td>0063-0064</td> <td>作用中的視訊基底位址</td> </tr> <tr> <td>001A-001B</td> <td>鍵盤緩衝區指標(頭)</td> <td>0065</td> <td>CRT模式暫存器</td> </tr> <tr> <td>001C-001D</td> <td>鍵盤緩衝區指標(尾)</td> <td>0066</td> <td>彩色圖形介面卡的暫存器</td> </tr> <tr> <td>001E-003D</td> <td>鍵盤緩衝區</td> <td>0067-006B</td> <td>卡帶磁帶資料區</td> </tr> <tr> <td>003E-0048</td> <td>磁碟資料區</td> <td>006C-0070</td> <td>計時器資料區</td> </tr> <tr> <td>0049</td> <td>目前的視訊模式</td> <td></td> <td></td> </tr> </table> <p>PC每個BIOS中斷都有特殊的功能，例如10號中斷是控制螢幕的函數、16號中斷可控制鍵盤、17號中斷可控制印表機、1A中斷可取得計時器、1C中斷則是一個每秒會被執行18.2次的時間中斷函數，重新設定該中斷可讓程式乘是每隔1/18.2秒就執行一次。這些中斷，其實就是一組預先燒錄於BIOS中，可以透過中斷程序呼叫的『裝置驅動程式』。表格 2 顯示了PC的中斷表，這些中斷在撰寫 PC 組合語言時，具有重要的功能，因為PC組合語言可透過這些中斷存取周邊裝置，而不是讓程式設計師直接透過記憶體映射的方式存取周邊裝置。</p> 表格 2：個人電腦PC的中斷表<br /> <table class="wiki-content-table"> <tr> <td>編號</td> <td>說明</td> <td>編號</td> <td>說明</td> </tr> <tr> <td>0</td> <td>除法錯誤</td> <td>19</td> <td>啟動程式載入器</td> </tr> <tr> <td>1</td> <td>單步追蹤</td> <td>1A</td> <td>本日時間(單位為18.2次/秒)</td> </tr> <tr> <td>2</td> <td>不可遮罩中斷</td> <td>1B</td> <td>鍵盤中斷</td> </tr> <tr> <td>3</td> <td>中斷點</td> <td>1C</td> <td>使用者計時器中斷</td> </tr> <tr> <td>4</td> <td>溢位</td> <td>1D</td> <td>視訊參數</td> </tr> <tr> <td>5</td> <td>列印螢幕</td> <td>1E</td> <td>磁碟參數</td> </tr> <tr> <td>6</td> <td>無效的運算碼</td> <td>1F</td> <td>繪圖表格</td> </tr> <tr> <td>7</td> <td>無法使用處理器擴充</td> <td>20</td> <td>終止程式</td> </tr> <tr> <td>8</td> <td>IRQ0計時器中斷(18.2次/秒)</td> <td>21</td> <td>MS-DOS服務</td> </tr> <tr> <td>9</td> <td>IRQ1 鍵盤中斷</td> <td>22</td> <td>MS-DOS終止服務</td> </tr> <tr> <td>A</td> <td>IRQ2 可程式化中斷控制器</td> <td>23</td> <td>MS-DOS中斷位址</td> </tr> <tr> <td>B</td> <td>IRQ3 序列通訊 (COM2)</td> <td>24</td> <td>MS-DOS嚴重錯誤位址</td> </tr> <tr> <td>C</td> <td>IRQ4序列通訊 (COM1)</td> <td>25</td> <td>絕對磁碟的讀取 (已棄用)</td> </tr> <tr> <td>D</td> <td>IRQ5 固定磁碟</td> <td>26</td> <td>絕對磁碟的寫入 (已棄用)</td> </tr> <tr> <td>E</td> <td>IRQ6 磁碟中斷</td> <td>27</td> <td>終止並且常駐 (已棄用)</td> </tr> <tr> <td>F</td> <td>IRQ7 平行印表機</td> <td>28-FF</td> <td>保留</td> </tr> <tr> <td>10</td> <td>視訊服務 (螢幕)</td> <td>33</td> <td>滑鼠控制</td> </tr> <tr> <td>11</td> <td>設備檢查</td> <td>34-3E</td> <td>浮點樹模擬</td> </tr> <tr> <td>12</td> <td>記憶體大小</td> <td>3F</td> <td>覆蓋 (Overlay) 管理程式</td> </tr> <tr> <td>13</td> <td>軟碟服務</td> <td>40-41</td> <td>固定磁碟的服務</td> </tr> <tr> <td>14</td> <td>非同步序列埠服務</td> <td>42-5F</td> <td>保留：特殊用途</td> </tr> <tr> <td>15</td> <td>卡帶控制器</td> <td>60-6B</td> <td>可供應用程式使用</td> </tr> <tr> <td>16</td> <td>鍵盤服務</td> <td>6C-7F</td> <td>保留：特殊用途</td> </tr> <tr> <td>17</td> <td>印表機服務</td> <td>80-F0</td> <td>保留：由 ROM-BASIC 使用</td> </tr> <tr> <td>18</td> <td>執行ROM中的BASIC</td> <td>F1-FF</td> <td>可供應用程式使用</td> </tr> </table> <p>舉例而言，由於 0x10 號中斷為螢幕的視訊服務，該服務可以用來設定游標位置，將螢幕上下捲動，顯示字元與字串等。因此、組合語言可以透過 int 10h在螢幕上顯示訊息。表格 3 顯示了BIOS第10號中斷的功能與參數設置表。</p> 表格 3. BIOS第10號中斷 – 螢幕銀幕控制的詳細功能<br /> <table class="wiki-content-table"> <tr> <td>AH</td> <td>功能</td> <td>參數</td> </tr> <tr> <td>0</td> <td>設置顯示方式</td> <td>AL=顯示模式（0～13H）</td> </tr> <tr> <td>1</td> <td>設置游標類型</td> <td>CH=游標開始行 CL=游標結束行</td> </tr> <tr> <td>2</td> <td>設置游標位置</td> <td>BH=頁號；DH/DL =行號/列號</td> </tr> <tr> <td>3</td> <td>讀游標位置</td> <td>BH=頁號</td> </tr> <tr> <td>5</td> <td>設置當前顯示頁</td> <td>AL=頁號</td> </tr> <tr> <td>6</td> <td>螢幕初始化或上卷</td> <td>AL=上卷行數；AL=0全螢幕為空白；BH=捲入行屬性；CH/CL=左上角行號/列號；DH/DL=右上角行號/列號</td> </tr> <tr> <td>7</td> <td>螢幕初始化或下卷</td> <td>AL=下卷行數；AL=0全螢幕為空白 BH=捲入行屬性 CH/CL=左上角行號/列號 DH/DL=右上角行號/列號</td> </tr> <tr> <td>8</td> <td>讀游標位置的屬性和字元</td> <td>BH=顯示頁號；AH=屬性；AL =字元</td> </tr> <tr> <td>9</td> <td>在游標位置顯示字元和屬性</td> <td>BH=顯示頁號；AL =字元 BL=屬性；CX=字元重複次數</td> </tr> <tr> <td>A</td> <td>在游標位置僅顯示字元</td> <td>BH=顯示頁號；AL =字元 CX=字元重複次數</td> </tr> <tr> <td>E</td> <td>顯示字元（游標前移）</td> <td>AL =字元；BL=前景色</td> </tr> <tr> <td>13</td> <td>顯示字串</td> <td>ES：BP=串地址；CX=串長 DH/DL=起始行/列號；BH=頁號 AL =模式；BL=屬性</td> </tr> </table> <p>那麼，要如何利用組合語言呼叫 int 中斷呢？範例 1 展示了一個利用BIOS中10號中斷以輸出 “Hello!” 字串的程式片段，該程式在設定了許多參數屬性後，利用int $0x10 指令呼叫BIOS，然後就會在銀幕上顯示是一個黑底紅字的 Hello! 字串。</p> <p>範例 1. 利用PC BIOS的10號中斷，輸出Hello!的範例 (AT&amp;T語法)</p> <div class="code"> <pre><code>… mov $msg, %ax mov %ax,%bp #ES:BP = 串地址 mov $6,%cx #CX = 串長度 mov $0x1301,%ax #AH = 13, AL = 01h mov $0x00C,%bx #頁號為0(BH = 0) 黑底紅字(BL = 0Ch,高亮) mov $0,%dl int $0x10 #10h 號中斷 ret msg:.ascii &quot;Hello!&quot; …</code></pre></div> <p>by <span class="printuser avatarhover"><a href="http://www.wikidot.com/user:info/ccckmit" ><img class="small" src="http://www.wikidot.com/avatar.php?userid=296763&amp;amp;size=small&amp;amp;timestamp=1786897297" alt="ccckmit" style="background-image:url(http://www.wikidot.com/userkarma.php?u=296763)" /></a><a href="http://www.wikidot.com/user:info/ccckmit" >ccckmit</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://ccckmit.wikidot.com/as:x86</guid>
				<title>IBM PC - Intel 的 x86 (IA32) 處理器架構</title>
				<link>http://ccckmit.wikidot.com/as:x86</link>
				<description>

&lt;div class=&quot;image-container aligncenter&quot;&gt;&lt;a href=&quot;http://ccckmit.wdfiles.com/local--files/as:x86/PC_architecture.jpg&quot;&gt;&lt;img src=&quot;http://ccckmit.wdfiles.com/local--resized-images/as:x86/PC_architecture.jpg/medium.jpg&quot; alt=&quot;PC_architecture.jpg&quot; class=&quot;image&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;圖一、個人電腦的結構圖&lt;/p&gt;
&lt;div class=&quot;image-container aligncenter&quot;&gt;&lt;a href=&quot;http://ccckmit.wdfiles.com/local--files/as:x86/PC_motherboard.jpg&quot;&gt;&lt;img src=&quot;http://ccckmit.wdfiles.com/local--resized-images/as:x86/PC_motherboard.jpg/medium.jpg&quot; alt=&quot;PC_motherboard.jpg&quot; class=&quot;image&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;圖二、個人電腦的主機板實例&lt;/p&gt;
&lt;div class=&quot;image-container aligncenter&quot;&gt;&lt;a href=&quot;http://ccckmit.wdfiles.com/local--files/as:x86/IA32_register.jpg&quot;&gt;&lt;img src=&quot;http://ccckmit.wdfiles.com/local--resized-images/as:x86/IA32_register.jpg/medium.jpg&quot; alt=&quot;IA32_register.jpg&quot; class=&quot;image&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;圖三、IA32 的常用暫存器&lt;/p&gt;
&lt;div class=&quot;image-container aligncenter&quot;&gt;&lt;a href=&quot;http://ccckmit.wdfiles.com/local--files/as:x86/IA32_eax.jpg&quot;&gt;&lt;img src=&quot;http://ccckmit.wdfiles.com/local--resized-images/as:x86/IA32_eax.jpg/medium.jpg&quot; alt=&quot;IA32_eax.jpg&quot; class=&quot;image&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;圖四、IA32 的 EAX 暫存器&lt;/p&gt;
&lt;h1&gt;&lt;span&gt;參考文獻&lt;/span&gt;&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;x86 Instruction Set Reference, &lt;a href=&quot;http://siyobik.info/index.php?module=x86&quot;&gt;http://siyobik.info/index.php?module=x86&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The Intel 8086 / 8088/ 80186 / 80286 / 80386 / 80486 Instruction Set, &lt;a href=&quot;http://home.comcast.net/~fbui/intel.html&quot;&gt;http://home.comcast.net/~fbui/intel.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Intel Architecture Software Developer&#039;s Manual - Volume 2&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://developer.intel.com/design/pentium/manuals/24319101.pdf&quot;&gt;http://developer.intel.com/design/pentium/manuals/24319101.pdf&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=296763&amp;amp;amp;size=small&amp;amp;amp;timestamp=1786897297&quot; alt=&quot;ccckmit&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=296763)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;ccckmit&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Tue, 27 Oct 2009 07:46:39 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <div class="image-container aligncenter"><a href="http://ccckmit.wdfiles.com/local--files/as:x86/PC_architecture.jpg"><img src="http://ccckmit.wdfiles.com/local--resized-images/as:x86/PC_architecture.jpg/medium.jpg" alt="PC_architecture.jpg" class="image" /></a></div> <p style="text-align: center;">圖一、個人電腦的結構圖</p> <div class="image-container aligncenter"><a href="http://ccckmit.wdfiles.com/local--files/as:x86/PC_motherboard.jpg"><img src="http://ccckmit.wdfiles.com/local--resized-images/as:x86/PC_motherboard.jpg/medium.jpg" alt="PC_motherboard.jpg" class="image" /></a></div> <p style="text-align: center;">圖二、個人電腦的主機板實例</p> <div class="image-container aligncenter"><a href="http://ccckmit.wdfiles.com/local--files/as:x86/IA32_register.jpg"><img src="http://ccckmit.wdfiles.com/local--resized-images/as:x86/IA32_register.jpg/medium.jpg" alt="IA32_register.jpg" class="image" /></a></div> <p style="text-align: center;">圖三、IA32 的常用暫存器</p> <div class="image-container aligncenter"><a href="http://ccckmit.wdfiles.com/local--files/as:x86/IA32_eax.jpg"><img src="http://ccckmit.wdfiles.com/local--resized-images/as:x86/IA32_eax.jpg/medium.jpg" alt="IA32_eax.jpg" class="image" /></a></div> <p style="text-align: center;">圖四、IA32 的 EAX 暫存器</p> <h1><span>參考文獻</span></h1> <ol> <li>x86 Instruction Set Reference, <a href="http://siyobik.info/index.php?module=x86">http://siyobik.info/index.php?module=x86</a></li> <li>The Intel 8086 / 8088/ 80186 / 80286 / 80386 / 80486 Instruction Set, <a href="http://home.comcast.net/~fbui/intel.html">http://home.comcast.net/~fbui/intel.html</a></li> <li>Intel Architecture Software Developer's Manual - Volume 2</li> <li><a href="http://developer.intel.com/design/pentium/manuals/24319101.pdf">http://developer.intel.com/design/pentium/manuals/24319101.pdf</a></li> </ol> <p>by <span class="printuser avatarhover"><a href="http://www.wikidot.com/user:info/ccckmit" ><img class="small" src="http://www.wikidot.com/avatar.php?userid=296763&amp;amp;size=small&amp;amp;timestamp=1786897297" alt="ccckmit" style="background-image:url(http://www.wikidot.com/userkarma.php?u=296763)" /></a><a href="http://www.wikidot.com/user:info/ccckmit" >ccckmit</a></span></p> 
				 	]]>
				</content:encoded>							</item>
					<item>
				<guid>http://ccckmit.wikidot.com/as:modify</guid>
				<title>組合語言 -- 最新修改</title>
				<link>http://ccckmit.wikidot.com/as:modify</link>
				<description>


&lt;p&gt;by &lt;span class=&quot;printuser avatarhover&quot;&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;&lt;img class=&quot;small&quot; src=&quot;http://www.wikidot.com/avatar.php?userid=296763&amp;amp;amp;size=small&amp;amp;amp;timestamp=1786897297&quot; alt=&quot;ccckmit&quot; style=&quot;background-image:url(http://www.wikidot.com/userkarma.php?u=296763)&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://www.wikidot.com/user:info/ccckmit&quot;  &gt;ccckmit&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
</description>
				<pubDate>Mon, 11 Oct 2010 06:52:02 +0000</pubDate>
												<content:encoded>
					<![CDATA[
						 <p>by <span class="printuser avatarhover"><a href="http://www.wikidot.com/user:info/ccckmit" ><img class="small" src="http://www.wikidot.com/avatar.php?userid=296763&amp;amp;size=small&amp;amp;timestamp=1786897297" alt="ccckmit" style="background-image:url(http://www.wikidot.com/userkarma.php?u=296763)" /></a><a href="http://www.wikidot.com/user:info/ccckmit" >ccckmit</a></span></p> 
				 	]]>
				</content:encoded>							</item>
				</channel>
</rss>