各位老鐵們,大家好,今天由我來為大家分享匯編語言add指令,以及add指令結果放到哪的相關問題知識,希望對大家有所幫助。如果可以幫助到大家,還望關注收藏下本站,您的支持是我們最大的動力,謝謝大家了哈,下面我們開始吧!
匯編語言如何發展到C語言的
我給你說說二者的區別,再去看看演變歷史!
一、匯編語言是什么?
我們知道,CPU只負責計算,本身不具備智能。你輸入一條指令(instruction),它就運行一次,然后停下來,等待下一條指令。這些指令都是二進制的,稱為操作碼(opcode),比如加法指令就是00000011。編譯器的作用,就是將高級語言寫好的程序,翻譯成一條條操作碼。對于人類來說,二進制程序是不可讀的,根本看不出來機器干了什么。為了解決可讀性的問題,以及偶爾的編輯需求,就誕生了匯編語言。匯編語言是二進制指令的文本形式,與指令是一一對應的關系。比如,加法指令00000011寫成匯編語言就是ADD。只要還原成二進制,匯編語言就可以被CPU直接執行,所以它是最底層的低級語言。二、來歷
最早的時候,編寫程序就是手寫二進制指令,然后通過各種開關輸入計算機,比如要做加法了,就按一下加法開關。后來,發明了紙帶打孔機,通過在紙帶上打孔,將二進制指令自動輸入計算機。為了解決二進制指令的可讀性問題,工程師將那些指令寫成了八進制。二進制轉八進制是輕而易舉的,但是八進制的可讀性也不行。很自然地,最后還是用文字表達,加法指令寫成ADD。內存地址也不再直接引用,而是用標簽表示。這樣的話,就多出一個步驟,要把這些文字指令翻譯成二進制,這個步驟就稱為assembling,完成這個步驟的程序就叫做assembler。它處理的文本,自然就叫做aseemblycode。標準化以后,稱為assemblylanguage,縮寫為asm,中文譯為匯編語言。每一種CPU的機器指令都是不一樣的,因此對應的匯編語言也不一樣。本文介紹的是目前最常見的x86匯編語言,即Intel公司的CPU使用的那一種。三、寄存器
學習匯編語言,首先必須了解兩個知識點:寄存器和內存模型。
先來看寄存器。CPU本身只負責運算,不負責儲存數據。數據一般都儲存在內存之中,CPU要用的時候就去內存讀寫數據。但是,CPU的運算速度遠高于內存的讀寫速度,為了避免被拖慢,CPU都自帶一級緩存和二級緩存。基本上,CPU緩存可以看作是讀寫速度較快的內存。但是,CPU緩存還是不夠快,另外數據在緩存里面的地址是不固定的,CPU每次讀寫都要尋址也會拖慢速度。因此,除了緩存之外,CPU還自帶了寄存器(register),用來儲存最常用的數據。也就是說,那些最頻繁讀寫的數據(比如循環變量),都會放在寄存器里面,CPU優先讀寫寄存器,再由寄存器跟內存交換數據。寄存器不依靠地址區分數據,而依靠名稱。每一個寄存器都有自己的名稱,我們告訴CPU去具體的哪一個寄存器拿數據,這樣的速度是最快的。有人比喻寄存器是CPU的零級緩存。四、寄存器的種類早期的x86CPU只有8個寄存器,而且每個都有不同的用途。現在的寄存器已經有100多個了,都變成通用寄存器,不特別指定用途了,但是早期寄存器的名字都被保存了下來。
●EAX●EBX●ECX●EDX●EDI●ESI●EBP●ESP
上面這8個寄存器之中,前面七個都是通用的。ESP寄存器有特定用途,保存當前Stack的地址(詳見下一節)。我們常常看到32位CPU、64位CPU這樣的名稱,其實指的就是寄存器的大小。32位CPU的寄存器大小就是4個字節。
五、內存模型:Heap
寄存器只能存放很少量的數據,大多數時候,CPU要指揮寄存器,直接跟內存交換數據。所以,除了寄存器,還必須了解內存怎么儲存數據。程序運行的時候,操作系統會給它分配一段內存,用來儲存程序和運行產生的數據。這段內存有起始地址和結束地址,比如從0x1000到0x8000,起始地址是較小的那個地址,結束地址是較大的那個地址。程序運行過程中,對于動態的內存占用請求(比如新建對象,或者使用malloc命令),系統就會從預先分配好的那段內存之中,劃出一部分給用戶,具體規則是從起始地址開始劃分(實際上,起始地址會有一段靜態數據,這里忽略)。舉例來說,用戶要求得到10個字節內存,那么從起始地址0x1000開始給他分配,一直分配到地址0x100A,如果再要求得到22個字節,那么就分配到0x1020。這種因為用戶主動請求而劃分出來的內存區域,叫做Heap(堆)。它由起始地址開始,從低位(地址)向高位(地址)增長。Heap的一個重要特點就是不會自動消失,必須手動釋放,或者由垃圾回收機制來回收。
六、內存模型:Stack
除了Heap以外,其他的內存占用叫做Stack(棧)。簡單說,Stack是由于函數運行而臨時占用的內存區域。請看下面的例子。
1234上面代碼中,系統開始執行main函數時,會為它在內存里面建立一個幀(frame),所有main的內部變量(比如a和b)都保存在這個幀里面。main函數執行結束后,該幀就會被回收,釋放所有的內部變量,不再占用空間。如果函數內部調用了其他函數,會發生什么情況?
12345上面代碼中,main函數內部調用了add_a_and_b函數。執行到這一行的時候,系統也會為add_a_and_b新建一個幀,用來儲存它的內部變量。也就是說,此時同時存在兩個幀:main和add_a_and_b。一般來說,調用棧有多少層,就有多少幀。等到add_a_and_b運行結束,它的幀就會被回收,系統會回到函數main剛才中斷執行的地方,繼續往下執行。通過這種機制,就實現了函數的層層調用,并且每一層都能使用自己的本地變量。所有的幀都存放在Stack,由于幀是一層層疊加的,所以Stack叫做棧。生成新的幀,叫做”入棧”,英文是push;棧的回收叫做”出棧”,英文是pop。Stack的特點就是,最晚入棧的幀最早出棧(因為最內層的函數調用,最先結束運行),這就叫做”后進先出”的數據結構。每一次函數執行結束,就自動釋放一個幀,所有函數執行結束,整個Stack就都釋放了。
Stack是由內存區域的結束地址開始,從高位(地址)向低位(地址)分配。比如,內存區域的結束地址是0x8000,第一幀假定是16字節,那么下一次分配的地址就會從0x7FF0開始;第二幀假定需要64字節,那么地址就會移動到0x7FB0。
七、CPU指令
7.1一個實例
了解寄存器和內存模型以后,就可以來看匯編語言到底是什么了。下面是一個簡單的程序example.c。
123456gcc將這個程序轉成匯編語言。
1上面的命令執行以后,會生成一個文本文件example.s,里面就是匯編語言,包含了幾十行指令。這么說吧,一個高級語言的簡單操作,底層可能由幾個,甚至幾十個CPU指令構成。CPU依次執行這些指令,完成這一步操作。example.s經過簡化以后,大概是下面的樣子。
12345678910111213可以看到,原程序的兩個函數add_a_and_b和main,對應兩個標簽_add_a_and_b和_main。每個標簽里面是該函數所轉成的CPU運行流程。每一行就是CPU執行的一次操作。它又分成兩部分,就以其中一行為例。
1這一行里面,push是CPU指令,%ebx是該指令要用到的運算子。一個CPU指令可以有零個到多個運算子。下面我就一行一行講解這個匯編程序,建議讀者最好把這個程序,在另一個窗口拷貝一份,省得閱讀的時候再把頁面滾動上來。
7.2push指令
根據約定,程序從_main標簽開始執行,這時會在Stack上為main建立一個幀,并將Stack所指向的地址,寫入ESP寄存器。后面如果有數據要寫入main這個幀,就會寫在ESP寄存器所保存的地址。然后,開始執行第一行代碼。
1push指令用于將運算子放入Stack,這里就是將3寫入main這個幀。雖然看上去很簡單,push指令其實有一個前置操作。它會先取出ESP寄存器里面的地址,將其減去4個字節,然后將新地址寫入ESP寄存器。使用減法是因為Stack從高位向低位發展,4個字節則是因為3的類型是int,占用4個字節。得到新地址以后,3就會寫入這個地址開始的四個字節。
1第二行也是一樣,push指令將2寫入main這個幀,位置緊貼著前面寫入的3。這時,ESP寄存器會再減去4個字節(累計減去8)。
7.3call指令
第三行的call指令用來調用函數。
1上面的代碼表示調用add_a_and_b函數。這時,程序就會去找_add_a_and_b標簽,并為該函數建立一個新的幀。下面就開始執行_add_a_and_b的代碼。
1這一行表示將EBX寄存器里面的值,寫入_add_a_and_b這個幀。這是因為后面要用到這個寄存器,就先把里面的值取出來,用完后再寫回去。這時,push指令會再將ESP寄存器里面的地址減去4個字節(累計減去12)。
7.4mov指令
mov指令用于將一個值寫入某個寄存器。
1這一行代碼表示,先將ESP寄存器里面的地址加上8個字節,得到一個新的地址,然后按照這個地址在Stack取出數據。根據前面的步驟,可以推算出這里取出的是2,再將2寫入EAX寄存器。下一行代碼也是干同樣的事情。
1上面的代碼將ESP寄存器的值加12個字節,再按照這個地址在Stack取出數據,這次取出的是3,將其寫入EBX寄存器。
7.5add指令
add指令用于將兩個運算子相加,并將結果寫入第一個運算子。
1上面的代碼將EAX寄存器的值(即2)加上EBX寄存器的值(即3),得到結果5,再將這個結果寫入第一個運算子EAX寄存器。
7.6pop指令
pop指令用于取出Stack最近一個寫入的值(即最低位地址的值),并將這個值寫入運算子指定的位置。
1上面的代碼表示,取出Stack最近寫入的值(即EBX寄存器的原始值),再將這個值寫回EBX寄存器(因為加法已經做完了,EBX寄存器用不到了)。注意,pop指令還會將ESP寄存器里面的地址加4,即回收4個字節。
add匯編語言是什么意思
匯編語言是二進制指令的文本形式,與指令是一一對應的關系。比如,加法指令00000011寫成匯編語言就是ADD。只要還原成二進制,匯編語言就可以被CPU直接執行,所以它是最底層的低級語言,稱為assemblylanguage,縮寫為asm,中文譯為匯編語言。
匯編語言中ADD DISP[BX][DI]
DISP是一個變量名或數組名。它代表一個內存地址。DISP[BX][DI]是相對的基址變址尋址方式,它表示這個操作數的有效地址由DISP地址值+BX寄存器內容+SI寄存器內容生成。
匯編語言中ADD和ADDC的區別是什么
ADD兩數相加,不加進位位。
ADDC兩數相加,同時再加個進位位。進位當時為1就加1為0就加0相當于不加
一般用在多字節數相加中。最低位相加,用ADD,加完后,可能產生進位,高字節相加就用ADDC
這樣,低字節相加產生的進位就會被加進來。
比如0080H+0180H
低字節相加用ADD
80H+80H=100H用ADD指令得到00H并溢出產生進位C=1
高字節相加用ADDC
00H+01H=01H用ADDC指令兩數相加結果01H會再加上進位位1得到02H
0080H+0180H=0200H
再比如
0080H+0101H
80H+01H=81H沒有溢出進位為C=0
00H+01H=01H用ADDC指令會再加進位位C=0得到01H
結果0080H+0101H=0181H
add sub是什么程序語言
addsub是匯編語言指令,指令(instruction)是一種語句,它在程序匯編編譯時變得可執行。匯編器將指令翻譯為機器語言字節,并且在運行時由CPU加載和執行。
一條指令有四個組成部分:
標號(可選)
指令助記符(必需)
操作數(通常是必需的)
注釋(可選)
關于本次匯編語言add指令和add指令結果放到哪的問題分享到這里就結束了,如果解決了您的問題,我們非常高興。