国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

匯編語言第一講:計(jì)算機(jī)的組織架構(gòu)和匯編語言介紹

這篇具有很好參考價(jià)值的文章主要介紹了匯編語言第一講:計(jì)算機(jī)的組織架構(gòu)和匯編語言介紹。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

  • 第一講:計(jì)算機(jī)的組織架構(gòu)和匯編語言介紹
    • 匯編語言
    • 計(jì)算機(jī)組織架構(gòu)
      • 數(shù)字電路
      • 術(shù)語回顧
      • 數(shù)制
    • 數(shù)字電路
      • 硬件電路
      • 數(shù)字電路的問題
    • 匯編語言的開始
      • 程序的節(jié)(sections)
      • 調(diào)用操作系統(tǒng)的系統(tǒng)調(diào)用
      • 列出文件(Listing files)
      • 匯編和鏈接
      • 調(diào)試匯編程序
      • 反匯編現(xiàn)有的程序
    • 附錄
      • 課程資源

第一講:計(jì)算機(jī)的組織架構(gòu)和匯編語言介紹

匯編語言

匯編語言和C/C++語言的區(qū)別是什么?

  • 匯編語言是底層語言,更接近于CPU本身可以理解的內(nèi)容。CPU可以理解的是純粹的字節(jié)流(機(jī)器語言)。幾乎不會(huì)有人愿意通過寫原始的字節(jié)流進(jìn)行編程。匯編語言處于機(jī)器語言的上層, 將CPU可以理解的操作碼(Opcode)抽象成了人類可以理解的命令, 例如add,mov等等。這些名字被稱之為助記符。

  • 和C/C++語言相比,匯編語言的工具較少。沒有所謂的"標(biāo)準(zhǔn)匯編語言庫"。如果你想要寫一個(gè)字符串處理的方法,你只能自己編寫。

  • 匯編語言不能移植到其他類型的CPU上(x86 vs ARM)或者其他類型的操作系統(tǒng)上(Windows vs Linux), 甚至不能和其它類型的匯編語言(YASM vs MASM vs GAS)都無法兼容。

一般來說, 我們編譯一個(gè)C/C++ 程序的流程如下所示:

                    compile                 link
C/C++ source code    -->      object code    -->    executable 

其中object code是指指令流, 這些指令將會(huì)被CPU直接運(yùn)行。C/C++中的一條語句可能會(huì)編譯成許多指令。即使是像下面這樣簡單的語句:

x = y;

上面的語句可能需要在CPU級(jí)別執(zhí)行大量的工作, 這取決于x和y在內(nèi)存中的位置,它們是否有相同的類型等等。

因此,我們使用高級(jí)語言(C/C++)編寫的"指令"的數(shù)量和CPU實(shí)際執(zhí)行的指令的數(shù)量上存在很大的差異。

但是匯編語言所編寫的指令和cpu實(shí)際執(zhí)行的指令是一一對(duì)應(yīng)的。匯編語言程序中的每一行代碼都保證翻譯成單個(gè) CPU 指令。一方面,這意味著匯編語言可以讓我們很好的掌握CPU正在執(zhí)行的工作, 另一方面,我們?cè)贑/C++語言中很方便實(shí)現(xiàn)的特性實(shí)際上在CPU層面都不存在。實(shí)際上,在CPU層面上并沒有所謂的for循環(huán),if-else條件分支,變量聲明等等。我們必須通過組合一些原始的操作來實(shí)現(xiàn)這些高級(jí)語言的特性。

由于匯編指令和CPU指令是一一對(duì)應(yīng)的,因此每種類型的CPU都有自己對(duì)應(yīng)的匯編語言。Intel CPU的匯編語言和ARM CPU(大多數(shù)智能手機(jī)使用ARM CPU)的匯編語言是完全不同的。并且與Arduino上使用的AVR CPU完全不同。與C/C++不同的是,匯編語言是無法做到移植性的。

即便我們使用同一種類型的CPU,也不能保證匯編器與操作系統(tǒng)之間的可移植性。與C/C++不同的是, C/C++由國際委員會(huì)決定C/C++的標(biāo)準(zhǔn),然而匯編語言卻不是這樣。因此,按照YASM(匯編器)寫出來的匯編代碼可能無法在GAS/NASM或者微軟的匯編器上進(jìn)行匯編。操作系統(tǒng)層面也會(huì)導(dǎo)致這樣的不兼容性,因?yàn)闆]有"標(biāo)準(zhǔn)匯編庫"。在一種操作系統(tǒng)下寫出的匯編程序可能無法移植到其他操作系統(tǒng)下。Windows下使用匯編語言寫出的程序移植到Linux下可能不能運(yùn)行,不僅僅是因?yàn)閰R編器不同,操作系統(tǒng)系統(tǒng)的接口不同也是一個(gè)重要原因。(Windows和Linux對(duì)于系統(tǒng)調(diào)用的定義不同)。

本課程使用的是 YASM 匯編器, 基于64位的Intel CPU(X86-64),在Linux系統(tǒng)下運(yùn)行。

我們會(huì)使用GDB調(diào)試器去調(diào)試你的匯編程序。在C++中,你最初用于調(diào)試程序的工具可能是在出錯(cuò)的位置附近添加cout,但是將打印添加到匯編程序中就可能需要重寫你需要打印的函數(shù),甚至重新所有的程序。顯示通過打印的方式調(diào)試程序在匯編語言的debug中是不可行的。所以我們?cè)谡n程中也會(huì)熟悉GDB工具。

計(jì)算機(jī)組織架構(gòu)

計(jì)算機(jī)組織架構(gòu)是指計(jì)算機(jī)的內(nèi)部結(jié)構(gòu)。內(nèi)存、CPU、I/O設(shè)備等如何連接在一起,如何配合起來工作。雖然我們主要關(guān)注我們實(shí)際使用的計(jì)算機(jī)的組織架構(gòu)(x86-64),但是有時(shí)我們也會(huì)去和其他的計(jì)算機(jī)系統(tǒng)進(jìn)行比較(MIPS, ARM等等)。當(dāng)然,記住這些不同的系統(tǒng)的區(qū)別也很重要。

數(shù)字電路

CPU通過數(shù)字電路來實(shí)現(xiàn),數(shù)字電路由邏輯門電路組成。這是比匯編語言更加底層的內(nèi)容。我們會(huì)稍微了解一下數(shù)字電路,僅僅是為了感受CPU是如何進(jìn)行工作的,但是課程的側(cè)重點(diǎn)還是在匯編語言上。

術(shù)語回顧

字節(jié)(Byte):可以單獨(dú)尋址的計(jì)算機(jī)內(nèi)存的最小單位。對(duì)于我們來說,一個(gè)Byte等于8個(gè)bit。但是需要了解的是并不是所有的系統(tǒng)都是這樣的。有一些奇怪的系統(tǒng),一個(gè)byte是10個(gè)bit或者7個(gè)bit。

每個(gè)byte中的每個(gè)bit的位置從右到左編號(hào)為0到7:

Bit value	0	0	1	0	1	1	0	1
Bit pos.	7	6	5	4	3	2	1	0

(word): 兩個(gè)字節(jié)(16 bits)。
將一個(gè)字視作2個(gè)字節(jié)時(shí),我們將第一個(gè)字節(jié)(占據(jù)低8位的字節(jié))稱之為"低字節(jié)", 將第二個(gè)字節(jié)稱之為"高字節(jié)"。

匯編語言第一講:計(jì)算機(jī)的組織架構(gòu)和匯編語言介紹,匯編語言,匯編

類似的,如果我們對(duì)一個(gè)字節(jié)中的bit的位置進(jìn)行編號(hào),則低字節(jié)的bit將編號(hào)為0-7,而高字節(jié)中的bit將編號(hào)為8-15。

這個(gè)規(guī)則可以推廣到雙字(dword)的低位字和高位字、四字(qword)的低位和高位雙字等等。類似的,在一個(gè)字節(jié)中,比特0代表低位, 比特7代表高位。

雙字(double-words/dword): 4個(gè)bytes(32個(gè)bits)

四字(Quad-word/qword): 8個(gè)bytes(64個(gè)bits)。(這個(gè)quad可以用quadra kill四殺來輔助記憶)

依次類推還有,雙四字(double-quad-words),16bytes, 四四字(“quad-quad-words”), 32 bytes, 等等。但是這些很少見,不常用。

KB:kilo-bytes(千字節(jié)), 這里的"kilo"指的是二進(jìn)制的千, 2 10 = 1024 {2}^{10} = 1024 210=1024字節(jié)。K后面跟著的大寫的B代表我們的單位是字節(jié),如果是小寫的b則代表是比特。

Kb:kilo-bit(千比特)。這個(gè)單位通常使用的不太多,在通訊領(lǐng)域中使用很多。例如帶寬通常以兆比特為單位進(jìn)行測(cè)量。

MB:Mega-byte(兆字節(jié)), 2 20 = 1024 2 = 1048576 {2}^{20} = {1024}^{2} = 1048576 220=10242=1048576字節(jié)。這個(gè)數(shù)量級(jí)大約是100萬字節(jié)。

GB: Gigabytes(千兆字節(jié)), 2 30 = 1024 3 = 1073741824 {2}^{30} = {1024}^{3} = 1073741824 230=10243=1073741824字節(jié)。這個(gè)數(shù)量級(jí)大約是10億字節(jié)。

以此類推還有TB、PB等等。

二進(jìn)制的百萬(million 1048576)和十進(jìn)制的百萬(1000000)的區(qū)別就解釋了磁盤標(biāo)簽上的容量和系統(tǒng)中實(shí)際顯示的容量的區(qū)別。操作系統(tǒng)使用二進(jìn)制的度量方式,而標(biāo)簽上印刷的是十進(jìn)制的度量方式。所以區(qū)別磁盤標(biāo)簽上的500GB在你的操作系統(tǒng)中顯示的容量將會(huì)是下面的數(shù)值:

     500,000,000,000
    ——————————————— = 465 GB
     1,073,741,824

數(shù)制

十進(jìn)制(Decimal):十進(jìn)制以10為基數(shù),這是我們經(jīng)常使用的。數(shù)字范圍是0-9。

二進(jìn)制(Binary): 二進(jìn)制的數(shù)字范圍是0-1。

八進(jìn)制(Octal):八進(jìn)制的數(shù)字范圍是0-7。(通常八進(jìn)制的使用相對(duì)較少)

十六進(jìn)制(Hexadecimal):十六進(jìn)制的數(shù)字范圍是0-9,a(10), b(11), c(12), d(13), e(14), f(15)。

接下來我們將回顧二進(jìn)制和十六進(jìn)制算術(shù)。

注意,這些數(shù)制,沒有那種一定比其他的類型更好或更正確。

   21   ==   10101b   ==   0x15   ==   025
decimal      binary        hex.       octal

在計(jì)算機(jī)系統(tǒng)的內(nèi)部,計(jì)算機(jī)使用二進(jìn)制存儲(chǔ)內(nèi)容。但是這個(gè)通常對(duì)于上層語言(包括匯編語言)而言,并不感知。 我們可以很容易的加減二進(jìn)制的數(shù)字或者其他進(jìn)制的數(shù)字。所以大多數(shù)時(shí)候,計(jì)算機(jī)底層使用二進(jìn)制并不會(huì)太影響我們編程。

C/C++ 和匯編都允許我們?cè)谏鲜鋈魏螖?shù)字系統(tǒng)的源代碼中編寫數(shù)字,只需使用不同的格式:

符號(hào) 數(shù)制
21 十進(jìn)制
10101b 二進(jìn)制,以b結(jié)尾
0x15 十六進(jìn)制,以0x開頭
025 八進(jìn)制,以0開頭

注意,b、0x等不是數(shù)字本身的一部分,它們僅僅用來區(qū)分不同的進(jìn)制。編譯器/匯編器負(fù)責(zé)將對(duì)應(yīng)的數(shù)字轉(zhuǎn)換為計(jì)算機(jī)使用的內(nèi)部格式。

例如,在下面的例子中,你可以這樣做:

int x = 21;

if(x == 0x15) { 
    ?
}

上面的if語句中的語句總是為true。

類似地,當(dāng)我們打印一個(gè)數(shù)字(通過 cout 或 printf)時(shí),它通常打印為十進(jìn)制,但通過各種標(biāo)志我們可以要求十六進(jìn)制。運(yùn)行時(shí)庫負(fù)責(zé)將內(nèi)部表示形式轉(zhuǎn)換回十進(jìn)制/十六進(jìn)制。在本學(xué)期晚些時(shí)候,我們將有一個(gè)手動(dòng)打印數(shù)字的作業(yè)(因?yàn)閰R編語言沒有標(biāo)準(zhǔn)庫來為我們做這件事?。?/p>

數(shù)字電路

CPU 由一組復(fù)雜的數(shù)字電路實(shí)現(xiàn)。數(shù)字電路是由邏輯門構(gòu)建的(邏輯門又是使用晶體管構(gòu)建的)。在數(shù)字電路設(shè)計(jì)中,在數(shù)字電路設(shè)計(jì)中,我們展示邏輯信號(hào)(開/關(guān)值)如何從輸入流經(jīng)邏輯門到輸出。如果有電流流過邏輯信號(hào),則邏輯信號(hào)為高(開);如果沒有電流(或電流非常?。?,則邏輯信號(hào)為低(關(guān))。

邏輯門的基本類型有:

  • 非門(NOT):單輸入、單輸出門,反轉(zhuǎn)其輸入。如果輸入為高電平,則輸出為低電平,反之亦然。
    匯編語言第一講:計(jì)算機(jī)的組織架構(gòu)和匯編語言介紹,匯編語言,匯編

    非(NOT) 在 C/C++ 中運(yùn)算符是~。這個(gè)符號(hào)是按位非,與邏輯非(!)不同。

  • 與門(AND):雙輸入、單輸出門:當(dāng)且僅當(dāng)兩個(gè)輸入均為高電平時(shí),輸出為高電平,否則為低電平。

    匯編語言第一講:計(jì)算機(jī)的組織架構(gòu)和匯編語言介紹,匯編語言,匯編

    AND 的 C/C++ 運(yùn)算符是 &(這是按位與,與 && 邏輯與 不同)。

  • 或門(OR):雙輸入、單輸出門:如果其中一個(gè)或兩個(gè)輸入都為高電平,則輸出為高電平,否則(如果兩個(gè)輸入均為低電平)輸出為低電平。

    匯編語言第一講:計(jì)算機(jī)的組織架構(gòu)和匯編語言介紹,匯編語言,匯編

    C/C++ 中與運(yùn)算符是 | (這又是按位或,不同于邏輯或 ||)

  • 異或門(XOR):雙輸入,單輸出門。如果其中一個(gè)輸入為高電平但不是兩個(gè)輸入都是高電平,則輸出為高電平。否則,當(dāng)兩個(gè)輸入都為高電平或者兩個(gè)輸入都是低電平,則輸出為低電平。實(shí)際上,如果輸入不同(一高一低),則輸出為高,如果輸入相同,則輸出為低。

    匯編語言第一講:計(jì)算機(jī)的組織架構(gòu)和匯編語言介紹,匯編語言,匯編

    C/C++中代表異或的運(yùn)算符是^(這個(gè)是按位異或, 沒有邏輯上的異或)。 注意^不是求冪運(yùn)算符,C/C++中沒有求冪的運(yùn)算符。

  • 與非門(NAND):輸出端帶有非門的與門。也就是說,如果兩個(gè)輸入都為高電平,則輸出為低電平,否則為高電平。

    匯編語言第一講:計(jì)算機(jī)的組織架構(gòu)和匯編語言介紹,匯編語言,匯編

    C/C++沒有直接的與非運(yùn)算符??梢允褂?code>&和~組合起來起到相同的效果。

  • 或非(NOR):在或門的輸出端帶有一個(gè)非門。如果兩個(gè)輸入均為低電平,則輸出為高電平,否則為低電平。

    匯編語言第一講:計(jì)算機(jī)的組織架構(gòu)和匯編語言介紹,匯編語言,匯編

    C/C++沒有直接的或非運(yùn)算符??梢允褂?code>|和~組合起來起到相同的效果。

  • 同或(XNOR):輸出端帶有非門的異或門。如果兩個(gè)輸入相同(均為低電平或均為高電平),則輸出為高電平,否則為低電平。

    匯編語言第一講:計(jì)算機(jī)的組織架構(gòu)和匯編語言介紹,匯編語言,匯編

    C/C++沒有直接的同或運(yùn)算符。可以使用^~組合起來起到相同的效果。

你可能會(huì)熟悉前三種邏輯門。有幾點(diǎn)需要注意:

  • 與門(AND)和或門(OR)可以擴(kuò)展為超過2個(gè)輸入端,n輸入的與門,當(dāng)它的所有的n個(gè)輸入端都是高電平時(shí),則該與門輸出高電平,否則為低電平。同樣,一個(gè)n輸入端的或門,只要有一個(gè)輸入端是高電平,則該或門將輸出高電平。如果所有的輸入都是低電平,則該或門輸出低電平。

下圖說明了如何構(gòu)建 3 輸入與門:

匯編語言第一講:計(jì)算機(jī)的組織架構(gòu)和匯編語言介紹,匯編語言,匯編

問題:如果異或門以相同的配置排列,所得的 3 輸入、1 輸出電路會(huì)起什么作用?

  • 與非門和或非門具有通用性:所有其他門都可以僅由 NAND 或 NOR 構(gòu)建。事實(shí)上,為了簡化制造,僅使用 NAND 門構(gòu)建電路是很常見的。

    例如,下面是一個(gè)相當(dāng)于僅使用 NAND 門實(shí)現(xiàn)的 A OR B 的電路(您應(yīng)該驗(yàn)證該電路是否為輸入 A 和 B 的所有四種組合生成正確的輸出)

    匯編語言第一講:計(jì)算機(jī)的組織架構(gòu)和匯編語言介紹,匯編語言,匯編

    您可以在維基百科上找到有關(guān)如何將所有其他類型的邏輯門轉(zhuǎn)換為 NAND 和 NOR 門的完整參考。作業(yè) 1 將要求您將使用 NOT、AND 和 OR 的電路轉(zhuǎn)換為僅使用 NAND 門的電路。

電路真值表

任何(無狀態(tài))m 輸入、n 輸出電路的行為也可以使用表格來說明,該表格顯示每個(gè)輸入組合如何映射到特定的輸出集。因?yàn)槊總€(gè)輸入可以是低 (0) 或高 (1),所以該表將有 2m 行和 m + n 列。例如,上面顯示的 3 輸入 AND:

匯編語言第一講:計(jì)算機(jī)的組織架構(gòu)和匯編語言介紹,匯編語言,匯編

Input Output
A B C Q
0 0 0 0
1 0 0 0
0 1 0 0
1 1 0 0
0 0 1 0
1 0 1 0
0 1 1 0
1 1 1 1

從表格中可以知道,僅當(dāng)所有三個(gè)輸入均為高電平 (1) 時(shí),輸出才為高電平 (1)。

硬件電路

如果您嘗試在實(shí)際電子硬件中實(shí)現(xiàn)邏輯電路,您會(huì)遇到上面未提及的幾個(gè)問題:

為了解決這個(gè)不可預(yù)測(cè)的時(shí)期,大多數(shù)數(shù)字電路都是同步的:他們使用時(shí)鐘來控制何時(shí)執(zhí)行計(jì)算。時(shí)鐘是一個(gè) 0 輸入、1 輸出的邏輯器件,它輸出一個(gè)信號(hào),該信號(hào)以規(guī)則的時(shí)鐘速率交替出現(xiàn)低、高、低、高……
通常,當(dāng)時(shí)鐘信號(hào)從低電平變?yōu)楦唠娖剑〞r(shí)鐘信號(hào)的“上升沿”)時(shí),電路的其余部分將執(zhí)行其計(jì)算,但直到下一個(gè)時(shí)鐘周期的上升沿才會(huì)讀取計(jì)算的輸出。

  • 電流不僅僅從 A 點(diǎn)流到 B 點(diǎn)(如邏輯圖所示),而且僅在存在閉合電路時(shí)才流動(dòng)。為了使得電路在實(shí)際中能夠工作,必須提供電路的最終輸出返回到輸入電源之間的連接。在真實(shí)的電路中,這些連接當(dāng)然會(huì)存在,但在邏輯圖中,我們忽略它們,因?yàn)樗鼈儾粫?huì)影響電路的邏輯及其實(shí)際計(jì)算的內(nèi)容。
    許多門電路都需要電源連接(始終為高電平的輸入)為其供電,這會(huì)使得現(xiàn)實(shí)中的電路更加復(fù)雜。
  • 如果你想嘗試只購買一個(gè)或門, 你會(huì)發(fā)現(xiàn)你無法僅僅買一個(gè)或門。門電路通常是在集成電路上使用,通常會(huì)將多個(gè)相同類型的門電路綁定在一起。例如,您可以購買在單個(gè)芯片上具有四個(gè)、八個(gè)或更多 NAND 門的 IC(集成電路)。這是有道理的,因?yàn)樵趯?shí)際的電路設(shè)計(jì)中,您很少只需要一個(gè)門。(該芯片將具有一個(gè)由所有柵極共享的單電源輸入)。
  • 理想情況下,我們將邏輯電路描述為信號(hào)瞬間從低電平切換到高電平,反之亦然,但在現(xiàn)實(shí)系統(tǒng)中這是不可能的。電路的上升時(shí)間是線路從低電平變?yōu)楦唠娖剿璧臅r(shí)間。在此過渡期間,流過連接的電流量介于 0 和 1 之間,這可能會(huì)導(dǎo)致電路輸出在短時(shí)間內(nèi)不可預(yù)測(cè)。
  • 為了解決這個(gè)不可預(yù)測(cè)的時(shí)期,大多數(shù)數(shù)字電路都是同步的:他們使用時(shí)鐘來控制何時(shí)執(zhí)行計(jì)算。時(shí)鐘是一個(gè) 0 輸入、1 輸出的邏輯器件,它輸出一個(gè)信號(hào),該信號(hào)以規(guī)則的時(shí)鐘速率交替出現(xiàn)低、高、低、高……通常,當(dāng)時(shí)鐘信號(hào)從低電平變?yōu)楦唠娖剑〞r(shí)鐘信號(hào)的“上升沿”)時(shí),電路的其余部分將執(zhí)行其計(jì)算,但直到下一個(gè)時(shí)鐘周期的上升沿才會(huì)讀取計(jì)算的輸出。因此,輸出有 1 個(gè)完整時(shí)鐘周期來穩(wěn)定在正確的值。
    事實(shí)上,即使信號(hào)很高,它仍然不會(huì)處于恒定水平;它只是高于某個(gè)標(biāo)記“低”和“高”之間分界線的閾值。
  • 在電氣方面,單個(gè)輸出無法連接到無限數(shù)量的其他設(shè)備;輸出的“扇出”是有限制的。
  • 邏輯門可以通過多種不同的方式以電子方式實(shí)現(xiàn),從而產(chǎn)生不同的邏輯系列,每個(gè)都有自己的電氣特性。例如,對(duì)于不同的系列,“低”與“高”的電壓水平可能非常不同。另請(qǐng)注意,在大多數(shù)系列中,“低”電平不是 0V,而是低于“高”電平的某些電壓電平。例如,晶體管-晶體管-邏輯 (TTL) 系列使用 0 至 0.8V(相對(duì)于地)之間的低電壓電平,以及 2 至 5V 的高電壓電平。 0.8 至 2V 之間的輸入信號(hào)處于“不可預(yù)測(cè)”范圍內(nèi),可能會(huì)被視為高或低,甚至在兩者之間波動(dòng)。

數(shù)字電路的問題

您可以嘗試構(gòu)建以下一些電路,以測(cè)試您對(duì)邏輯電路的理解:

  • 使用你喜歡的任何邏輯門器件,去構(gòu)建一個(gè)4輸入 1輸出的電路, 當(dāng)且僅當(dāng)其中一個(gè)輸入為高電平時(shí)才輸出高電平。
  • 使用你喜歡的任何邏輯門器件,去構(gòu)建一個(gè)4輸入 1輸出的電路, 當(dāng)且僅當(dāng)有兩個(gè)輸入為高電平時(shí)才輸出高電平。
  • 僅使用 NAND,構(gòu)建一個(gè)比較器電路,一個(gè) 2 輸入、1 輸出電路,如果滿足以下條件,則輸出為高電平:
    • 兩個(gè)輸入都是低電平
    • 第一個(gè)輸入為高電平,第二個(gè)輸入是低電平
    • 兩個(gè)輸入都是高電平
      這等價(jià)于檢查是否第一個(gè)輸入小于等于第二個(gè)輸入。

這些問題有許多不同的可能解決方案。數(shù)字電路的進(jìn)階課程將教授優(yōu)化電路設(shè)計(jì)的方法,以便最大限度地減少所使用的門的數(shù)量。

匯編語言的開始

這里我們將使用匯編語言去編寫一個(gè)經(jīng)典的程序: Hello World程序。我們可以使用兩種廣泛的風(fēng)格來編寫匯編(.asm 程序)。

  • 我們可以通過調(diào)用操作系統(tǒng)的系統(tǒng)調(diào)用來與操作系統(tǒng)交互。由于缺少更好的名稱,我們稱之為系統(tǒng)調(diào)用風(fēng)格(syscall-style)。這是最直接的方法,但是操作起來不太方便。如果我們使用這種方式,那么我們的匯編程序的入口程序就是_start,我們首先使用系統(tǒng)調(diào)用向標(biāo)準(zhǔn)輸出打印一個(gè)字符串,使用另外一個(gè)系統(tǒng)調(diào)用退出。

    如果我們使用系統(tǒng)調(diào)用風(fēng)格,我們的程序?qū)⑹峭耆?dú)立的:除了我們編寫的內(nèi)容之外,生成的可執(zhí)行文件中不會(huì)有任何內(nèi)容。

  • 我們可以使用標(biāo)準(zhǔn)c庫中的方法例如printfexit。這稱之為"C庫風(fēng)格"。這就需要我們自己去鏈接c語言庫。這個(gè)方法顯然要強(qiáng)大得多,因?yàn)樗鼘標(biāo)準(zhǔn)庫中的所有資源都給了我們的程序。

    如果我們使用C庫的風(fēng)格,那么最終生成的可執(zhí)行文件將不僅包括我們編寫的代碼,還包括標(biāo)準(zhǔn)庫添加的很多的代碼。

下面我們先使用第一種風(fēng)格(系統(tǒng)調(diào)用風(fēng)格)編寫程序,這個(gè)方式上手更快一些。

;;; 
;;; hello.s
;;; Prints "Hello, world!"
;;;

section .data

msg:            db      "Hello, world!", 10
MSGLEN:         equ     $-msg

section .text

;; Program code goes here

global _start
_start:

    mov     rax,    1               ; Syscall code in rax
    mov     rdi,    1               ; 1st arg, file desc. to write to
    mov     rsi,    msg             ; 2nd arg, addr. of message
    mov     rdx,    MSGLEN          ; 3rd arg, num. of chars to print
    syscall

    ;; Terminate process
    mov     rax,    60              ; Syscall code in rax
    mov     rdi,    0               ; First parameter in rdi
    syscall                         ; End process

可以使用下面的命令進(jìn)行匯編和鏈接:

asm hello.s

也可以手動(dòng)進(jìn)行:

yasm -g dwarf2 -f elf64 hello.s -l hello.lst
ld -g -o hello hello.o

然后執(zhí)行像下面這樣執(zhí)行:

./hello

將打印出下面這樣的內(nèi)容:

Hello, world!

打印后會(huì)退出。

一步一步分解該程序,每行均包含以下形式:

label:       instruction       ; comment

所有這些內(nèi)容都是可選的,因此只有幾行是以label開頭, 并且很多行沒有注釋。 Label后面的冒號(hào)(:)也是可選的,但是為了程序的清晰,最好寫上。

解釋
section .data data節(jié),包含初始化的常量和變量
msg: db “Hello, world!”, 10 msg定義了一個(gè)指向"Hello,world!“字符串的標(biāo)簽,它將被逐字復(fù)制到我們的匯編程序中。db代表"define byte”,即定義字節(jié),最后的10,在ascii表中代表LF(\n)。注意用匯編的 db 偽指令定義字符串,不會(huì)自動(dòng)添加"\0",這個(gè)要和C/C++相區(qū)別
MSGLEN: equ $-msg equ定義了一個(gè)常量叫做MSGLEN, 這個(gè)常量代表的是msg的長度, $代表當(dāng)前的位置
section .text text節(jié)定義了程序的實(shí)際執(zhí)行的代碼
global _start 我們將_start標(biāo)簽聲明為全局,以便在程序之外可見(以便操作系統(tǒng)可以找到它可以啟動(dòng)我們的程序)
_start 這將 _start聲明為指向程序中當(dāng)前位置的標(biāo)簽
mov rax, 1 這會(huì)將值 1 加載到寄存器 rax中,該寄存器存儲(chǔ)系統(tǒng)調(diào)用代碼。 1 是"寫入文件"的系統(tǒng)調(diào)用代碼
mov rdi, 1 將 1 存儲(chǔ)到寄存器 rdi中。這是系統(tǒng)調(diào)用 write的第一個(gè)參數(shù),它是文件描述符(1 是標(biāo)準(zhǔn)輸出)
mov rsi, msg msg、地址存儲(chǔ)到 rsi中, 這是第二個(gè)參數(shù),表示要寫的消息
mov rdx, MSGLEN MSGLEN存儲(chǔ)到 rdx中。這是第三個(gè)參數(shù),即要寫入的長度(以字節(jié)為單位)
syscall 調(diào)用rax中存儲(chǔ)的值所代表的系統(tǒng)調(diào)用,打印字符
mov rax, 60 60 是"退出進(jìn)程"的系統(tǒng)調(diào)用代碼
mov rdi, 0 第一個(gè)參數(shù),0,退出代碼(成功)
syscall 執(zhí)行系統(tǒng)調(diào)用

注意: 對(duì)于匯編語言而言,默認(rèn)的后綴是.s。

對(duì)于Intel 語法而言, mov指令的結(jié)構(gòu)如下所示:

mov dest, src

即mov后先跟著目的對(duì)象,再接著是源對(duì)象。將其理解為dest = src是可以的。

程序的節(jié)(sections)

內(nèi)存中正在運(yùn)行的程序,其內(nèi)存空間分為許多不同的"部分"。盡管所有部分都是同一地址空間的一部分,但它們?cè)诟拍钌嫌糜诓煌挠猛荆⑶也僮飨到y(tǒng)可能對(duì)其應(yīng)用不同的權(quán)限。例如,操作系統(tǒng)通常將.text部分(可執(zhí)行機(jī)器代碼所在的位置)設(shè)置為只讀,因?yàn)樽孕薷拇a(通常)要么是錯(cuò)誤,要么是漏洞利用。

一個(gè)進(jìn)程的內(nèi)存布局通常如下所示:

--------------------
Stack (grows down)
…
Heap (grows up)
---------------------
.data section (global variables)
---------------------
.text section
---------------------

棧向下增長這一點(diǎn)很重要, 這代表壓棧操作會(huì)使得棧頂指針減少。

除了用于存放全局變量的.data節(jié)之外,還有一塊是.bss節(jié),其用于存放未經(jīng)過初始化的全局?jǐn)?shù)據(jù)。.data.bss的區(qū)別在于當(dāng)程序運(yùn)行時(shí),操作系統(tǒng)會(huì)將.data中的數(shù)據(jù)從磁盤中拷貝到內(nèi)存中。而.bss節(jié)中由于存放的是未經(jīng)過初始化的數(shù)據(jù),因此操作系統(tǒng)不需要復(fù)制任何內(nèi)容,只需要預(yù)留好對(duì)應(yīng)的空間即可。(還有一些其他類型的節(jié),不過我們目前不會(huì)用到,例如.readonly)

通過定義更多常量,可以使上面的程序更容易閱讀,例如:

section .data

SYS_write       equ     1
SYS_stdout      equ     1
SYS_exit        equ     60
EXIT_SUCCESS    equ     0

equ定義了一個(gè)匯編時(shí)的常量,當(dāng)程序運(yùn)行的時(shí)候,這些常量不會(huì)在內(nèi)存中占據(jù)任何的空間。 這有點(diǎn)類似與C/C++語言中的#define。

使用它們時(shí),我們只需通過名稱來引用它們:

mov     rax,  SYS_exit 
mov     rdi,  EXIT_SUCCESS
syscall

db將字節(jié)序列直接存儲(chǔ)到可執(zhí)行文件中, 例如下面的代碼:

msg  db  "Hello, world!", 10

其實(shí)際上做了兩件事情:

  • "Hello,world!"連同后面的10一同被寫入了可執(zhí)行文件中。
  • msg定義了一個(gè)標(biāo)簽,該標(biāo)簽指向了字節(jié)序的開始的地址。注意我們并不是將字符串的存入了msg中,而是將字符串的地址存入了msg中。

因?yàn)槲覀兪褂孟到y(tǒng)調(diào)用風(fēng)格,所以我們的字符串不以終止符 NULL (\0) 字符結(jié)尾。(上面的字符串以 10 結(jié)尾,即換行的 ASCII 字符;這就是在 C/C++ 中使用 \n 字符轉(zhuǎn)義時(shí)得到的結(jié)果。) 我們必須知道要傳遞給 SYS_write 系統(tǒng)調(diào)用的字符串的長度。我們可以簡單地手動(dòng)計(jì)算字節(jié)數(shù),但如果我們更改字符串的內(nèi)容,就需要重新計(jì)算字符串的長度。

如前所述,匯編器將字符串 msg放入生成的可執(zhí)行文件中的某個(gè)地址。事實(shí)上,我們的匯編源文件中的所有內(nèi)容都有一些地址,它將最終出現(xiàn)在生成的可執(zhí)行文件中。即使像 MSGLEN這樣理論上占用 0 空間的東西也有輸出文件中"當(dāng)前位置"的一些概念。$獲取當(dāng)前位置的地址。$-msg從當(dāng)前地址減去地址msg,得到 msg 指向的字符串的長度。需要注意的是,這只在定義 msg之后立即定義了 MSGLEN才會(huì)有效;如果中間有任何其他定義占用了文件中的空間,則計(jì)算出的長度將是錯(cuò)誤的。

(這也表明 equ定義可以在其值中使用有限的算術(shù);計(jì)算是在匯編時(shí)完成的,而不是在運(yùn)行時(shí)完成的。)

在我們所有的程序中,我們首先是 .data部分,然后是 .text部分,但這只是一個(gè)約定。您可以更改各部分的順序,甚至可以將它們交錯(cuò)排列,您的程序仍然可以運(yùn)行。

調(diào)用操作系統(tǒng)的系統(tǒng)調(diào)用

調(diào)用系統(tǒng)調(diào)用的過程如下:

  • rax設(shè)置為要執(zhí)行的系統(tǒng)調(diào)用的編號(hào)。例如SYS_exit的系統(tǒng)調(diào)用編號(hào)為60, 而SYS_write的系統(tǒng)調(diào)用編號(hào)為1。你可以在這里找到所有系統(tǒng)調(diào)用的編號(hào)。
  • rdi,rsi,rdxr10,r8,r9設(shè)置為系統(tǒng)調(diào)用函數(shù)的第一個(gè)、第二個(gè)、第三個(gè)參數(shù)。往后以此類推。
  • 執(zhí)行系統(tǒng)調(diào)用```syscall``指令。

請(qǐng)注意,步驟 (1) 和 (2) 可以按任何順序發(fā)生,但在執(zhí)行系統(tǒng)調(diào)用之前必須正確設(shè)置所有寄存器值。如果系統(tǒng)調(diào)用返回一個(gè)值(SYS_writeSYS_exit都沒有),則系統(tǒng)調(diào)用返回后該值將位于 rax中。

列出文件(Listing files)

yasm命令中的 -l noop.lst參數(shù)是可選的;它指示 YASM 生成一個(gè)列表文件,這是我們逐行編寫的匯編指令及其十六進(jìn)制操作碼的列表。以下是上述程序的列表文件:

     1                                 %line 1+1 hello_bare.s
     2                                 
     3                                 
     4                                 
     5                                 
     6                                 
     7                                 [section .data]
     8                                 
     9 00000000 48656C6C6F2C20776F-    msg db "Hello, world!", 10
    10 00000000 726C64210A         
    11                                 MSGLEN equ $-msg
    12                                 
    13                                 [section .text]
    14                                 
    15                                 
    16                                 
    17                                 [global _start]
    18                                 _start:
    19                                 
    20 00000000 48C7C001000000          mov rax, 1
    21 00000007 48C7C701000000          mov rdi, 1
    22 0000000E 48C7C6[00000000]        mov rsi, msg
    23 00000015 48BA0E000000000000-     mov rdx, MSGLEN
    24 00000015 00                 
    25 0000001F 0F05                    syscall
    26                                 
    27                                 
    28 00000021 48C7C03C000000          mov rax, 60
    29 00000028 48C7C700000000          mov rdi, 0
    30 0000002F 0F05                    syscall

第一列是原始行號(hào),第二列是匯編程序中相對(duì)于當(dāng)前節(jié)的地址(從 00000000 開始),第三列是操作碼,第四列是我們的原始程序。

從這里看, mov rax, 60的操作碼是48C7C03C000000mov rdi, 0操作碼是48C7C700000000 , syscall的操作碼是0F05。(x86-64 使用不同的指令寬度:并非所有操作碼的字節(jié)數(shù)都相同;有些較短,有些較長)

匯編和鏈接

asm腳本負(fù)責(zé)在所有輸入文件上運(yùn)行匯編程序,然后將它們鏈接在一起。 它還能正確檢測(cè)您是否將 _startmain定義為程序的入口點(diǎn),并在后一種情況下與C 標(biāo)準(zhǔn)庫鏈接。

如果你想進(jìn)行手動(dòng)匯編,則需要執(zhí)行的命令如下所示:

yasm -g dwarf2 -f elf64 filename.s -l filename.lst
  • -g 參數(shù)給出了調(diào)試信息使用的格式,以便 GDB(參見下一節(jié))可以讀取它。
  • -f 參數(shù)表示輸出 x86-64 格式的目標(biāo)文件。
  • -l 參數(shù)表示輸出列表文件。

要將一個(gè)(或多個(gè))匯編的目標(biāo)文件鏈接到一起成為可執(zhí)行文件,有兩種選擇:

  • 如果您沒有使用任何 C 標(biāo)準(zhǔn)庫函數(shù),并且程序的入口點(diǎn)名為 _start,則使用 ld:

    ld -g -o exe_name object.o files.o ...
    
  • 如果您使用的是 C 標(biāo)準(zhǔn)庫中的函數(shù),并且入口點(diǎn)名為 main,則使用 gcc:

     gcc -o exe_name object.o files.o ...
    

    這與用于鏈接 C 程序的目標(biāo)文件的命令行相同。 (事實(shí)上??,它可以用來鏈接由 C 和匯編語言混合組成的程序?。?/p>

(asm 腳本檢查是否有任何文件定義了 main;如果定義了 main,則假定您要使用 C 標(biāo)準(zhǔn)庫函數(shù)。)

調(diào)試匯編程序

GDB可以識(shí)別匯編語言,我們可以通過以下方式在 GDB 中運(yùn)行我們的程序

gdb ./hello

我們可以通過以下方式在程序的_start處打上斷點(diǎn):

break _start
run

然后使用 n(next) 命令逐行執(zhí)行程序。寄存器的值可以按名稱打印,前綴為 $,例如

print $rax

或更改它們:

set $rax = 0

您還可以使用info registers一次打印所有寄存器。

請(qǐng)注意,當(dāng)我使用 GDB 時(shí),我使用一個(gè)名為GDB dashboard的插件,它顯示每一步的寄存器內(nèi)容。

GDB 將默認(rèn)使用 AT&T語法進(jìn)行匯編。您可以通過輸入命令將其切換為 Intel語法。

set disassembly-flavor intel

您可以將此命令放入 ~/.gdbinit中,以便所有GDB會(huì)話都會(huì)有這樣的設(shè)置。

反匯編現(xiàn)有的程序

您可以使用 objdump反匯編已編譯的可執(zhí)行文件。這對(duì)你弄清楚C/C++程序在匯編層面如何執(zhí)行非常有用。當(dāng)然,結(jié)果通常并不像您想象的那么有用, 因?yàn)榫幾g器可能對(duì)您的代碼做了一些"有趣"的事情。編譯器的目標(biāo)是使生成的程序集更快,但并不容易理解。

#include <stdio.h>

int main() {
    printf("Hello, world!\n");
    return 0;
}

使用如下的命令進(jìn)行編譯:

gcc -c hello.c

這里會(huì)產(chǎn)生hello.o的目標(biāo)文件。我們可以對(duì)其反匯編:

objdump -d -M intel hello.o

輸出如下:


hello.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
   0:   55                      push   rbp
   1:   48 89 e5                mov    rbp,rsp
   4:   bf 00 00 00 00          mov    edi,0x0
   9:   e8 00 00 00 00          call   e <main+0xe>
   e:   b8 00 00 00 00          mov    eax,0x0
  13:   5d                      pop    rbp
  14:   c3                      ret  

這里看不到太多有用的東西。因?yàn)樗蕾嚵撕芏鄻?biāo)準(zhǔn)庫提供的很多方法的實(shí)現(xiàn), 而目前我們還沒有對(duì)它們進(jìn)行鏈接。目前對(duì)于調(diào)用printf的地方,只是用了占位符進(jìn)行替代。

上面的步驟,我們只是對(duì)目標(biāo)文件進(jìn)行了反匯編,而不是鏈接后的可執(zhí)行文件。

我們可以對(duì)hello.o鏈接成一個(gè)可執(zhí)行文件,執(zhí)行如下的命令:

gcc -o hello hello.o

然后使用objdump -d -M intel hello,我們將會(huì)得到更多的匯編內(nèi)容。標(biāo)準(zhǔn)庫在運(yùn)行 main()之前做了很多設(shè)置,并且可執(zhí)行文件包含所有這些代碼。另一方面,它讓我們看到了最終的 main是什么樣子的:

0000000000400507 <main>:
  400507:   55                      push   rbp
  400508:   48 89 e5                mov    rbp,rsp
  40050b:   bf a4 05 40 00          mov    edi,0x4005a4
  400510:   e8 eb fe ff ff          call   400400 <puts@plt>
  400515:   b8 00 00 00 00          mov    eax,0x0
  40051a:   5d                      pop    rbp
  40051b:   c3                      ret    
  40051c:   0f 1f 40 00             nop    DWORD PTR [rax+0x0]

從連接后的反匯編的代碼中,我們知道:

在這里,空的調(diào)用已經(jīng)被替換為過程調(diào)用的puts(puts@plt), 這個(gè)過程調(diào)用的內(nèi)部實(shí)現(xiàn)了printf的功能。

main是一個(gè)過程;它是從_start標(biāo)簽(標(biāo)準(zhǔn)庫提供) 調(diào)用的,并且必須在完成后返回,因此它以ret指令結(jié)束。

前兩條指令push rbp; mov rbp,rsp也是每個(gè)過程開始的標(biāo)準(zhǔn)寫法,這個(gè)在后續(xù)的章節(jié)中會(huì)學(xué)習(xí)到。

閱讀反匯編的其余部分,你可以研究 _start過程以及 puts的定義。

附錄

課程資源

課程原文: https://staffwww.fullcoll.edu/aclifton/cs241/lecture-introduction.html

相關(guān)課程: https://www.cs.uaf.edu/2017/fall/cs301/lecture/09_13_memory.html文章來源地址http://www.zghlxwxcb.cn/news/detail-845084.html

到了這里,關(guān)于匯編語言第一講:計(jì)算機(jī)的組織架構(gòu)和匯編語言介紹的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 匯編語言—常見匯編指令匯總

    mov? ? 寄存器 ,數(shù)據(jù)? ? ? ? ? ? ? ? 如:mov ax ,8 mov? ?寄存器,寄存器? ? ? ? ? ? ? 如:mov ax,bx mov? ?寄存器,內(nèi)存單元????????? 如:mov ax,[0] mov? ?內(nèi)存單元,寄存器? ????????如:mov [0],ax mov? ?段寄存器,寄存器? ????????如:mov ds,ax add? ?寄存器,數(shù)據(jù)

    2024年02月10日
    瀏覽(15)
  • 5.6 匯編語言:匯編高效數(shù)組尋址

    數(shù)組和指針都是用來處理內(nèi)存地址的操作,二者在C語言中可以互換使用。數(shù)組是相同數(shù)據(jù)類型的一組集合,這些數(shù)據(jù)在內(nèi)存中是連續(xù)存儲(chǔ)的,在C語言中可以定義一維、二維、甚至多維數(shù)組。多維數(shù)組在內(nèi)存中也是連續(xù)存儲(chǔ)的,只是數(shù)據(jù)的組織方式不同。在匯編語言中,實(shí)現(xiàn)

    2024年02月11日
    瀏覽(26)
  • 5.8 匯編語言:匯編高效除法運(yùn)算

    通常情況下計(jì)算除法會(huì)使用 div/idiv 這兩條指令,該指令分別用于計(jì)算無符號(hào)和有符號(hào)除法運(yùn)算,但除法運(yùn)算所需要耗費(fèi)的時(shí)間非常多,大概需要比乘法運(yùn)算多消耗10倍的CPU時(shí)鐘,在Debug模式下,除法運(yùn)算不會(huì)被優(yōu)化,但Release模式下,除法運(yùn)算指令會(huì)被特定的算法經(jīng)過優(yōu)化后轉(zhuǎn)

    2024年02月11日
    瀏覽(16)
  • 5.7 匯編語言:匯編高效乘法運(yùn)算

    乘法指令是一種在CPU中實(shí)現(xiàn)的基本算術(shù)操作,用于計(jì)算兩個(gè)數(shù)的乘積。在匯編語言中,乘法指令通常是通過 mul(無符號(hào)乘法) 和 imul(有符號(hào)乘法) 這兩個(gè)指令實(shí)現(xiàn)的。由于乘法指令在執(zhí)行時(shí)所消耗的時(shí)鐘周期較多,所以編譯器在優(yōu)化代碼時(shí)通常會(huì)嘗試將乘法操作轉(zhuǎn)換為更

    2024年02月11日
    瀏覽(20)
  • 5.10 匯編語言:匯編過程與結(jié)構(gòu)

    過程的實(shí)現(xiàn)離不開堆棧的應(yīng)用,堆棧是一種后進(jìn)先出 (LIFO) 的數(shù)據(jù)結(jié)構(gòu),最后壓入棧的值總是最先被彈出,而新數(shù)值在執(zhí)行壓棧時(shí)總是被壓入到棧的最頂端,棧主要功能是暫時(shí)存放數(shù)據(jù)和地址,通常用來保護(hù)斷點(diǎn)和現(xiàn)場(chǎng)。 棧是由 CPU 管理的線性內(nèi)存數(shù)組,它使用兩個(gè)寄存器 (S

    2024年02月11日
    瀏覽(21)
  • 南京郵電大學(xué)匯編語言程序設(shè)計(jì)實(shí)驗(yàn)一(匯編語言語法練習(xí)與代碼轉(zhuǎn)換)

    南京郵電大學(xué)匯編語言程序設(shè)計(jì)實(shí)驗(yàn)一(匯編語言語法練習(xí)與代碼轉(zhuǎn)換)

    排除語法錯(cuò)誤:給出的是一個(gè)通過比較法完成8位二進(jìn)制數(shù)轉(zhuǎn)換成十進(jìn)制數(shù)送屏幕顯示功能的匯編語言源程序,但有很多語法錯(cuò)誤。要求實(shí)驗(yàn)者按照原樣對(duì)源程序進(jìn)行編輯,匯編后,根據(jù)TASM給出的信息對(duì)源程序進(jìn)行修改,知道沒有語法錯(cuò)誤為止。然后進(jìn)行鏈接,并執(zhí)行相應(yīng)可

    2024年02月08日
    瀏覽(30)
  • 低級(jí)語言匯編真的各個(gè)面不如匯編嗎?

    低級(jí)語言匯編真的各個(gè)面不如匯編嗎?

    今日話題,低級(jí)語言匯編真的各個(gè)面不如C語言嗎?C語言因其可移植性、開發(fā)效率和可讀性而在各領(lǐng)域廣泛使用,市場(chǎng)占有率極高。然而,匯編語言在特定場(chǎng)景下仍然具有獨(dú)特優(yōu)勢(shì),穩(wěn)固地占據(jù)一席之地。如果你對(duì)這方面感興趣,我可以分享一套包含各類語言和嵌入式行業(yè)教

    2024年02月06日
    瀏覽(20)
  • 在C語言中調(diào)用匯編語言的函數(shù)

    在C語言中調(diào)用匯編文件中的函數(shù),要做的主要工作有兩個(gè): 一是在C語言中聲明函數(shù)原型,并加extern; 二是在匯編中用EXPORT導(dǎo)出函數(shù)名,并用該函數(shù)名作為匯編代碼段的標(biāo)識(shí),最后用mov pc, lr返回。然后,就可以在C語言中使用該函數(shù)了。 從C語言的角度,并不知道該函

    2024年02月14日
    瀏覽(28)
  • ARM匯編語言(2)

    ARM匯編語言是一種低級(jí)別的計(jì)算機(jī)指令集架構(gòu)(ISA)語言,它是ARM處理器上的一種指令集架構(gòu),用于編寫底層的系統(tǒng)軟件,例如操作系統(tǒng)、驅(qū)動(dòng)程序和嵌入式系統(tǒng)應(yīng)用程序。 ARM匯編語言使用基于寄存器的指令集,其中指令操作的數(shù)據(jù)通常存儲(chǔ)在處理器的寄存器中,而不是內(nèi)存

    2024年02月02日
    瀏覽(23)
  • 匯編語言中斷編程步驟

    1、調(diào)用movsb指令將中斷處理程序載入內(nèi)存的指定位置; 1)使用offset指令計(jì)算doIntEnd-doInt獲取中斷處理程序的代碼長度; 2)doIntEnd位置使用nop指令。 2、修改中斷向量表項(xiàng)為指定位置; 1)使用word ptr確定內(nèi)存單元; 2)使用es=0來定位中斷向量表首地址。 3、編寫中斷處理程序。

    2024年02月07日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包