



版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、Linux 中的匯編語言在閱讀 Linux 源代碼時,你可能碰到一些匯編語言片段,有些匯編語言出現(xiàn)在以.S為擴(kuò)展名的匯編文件中,在這種文件中,整個程序全部由匯編語言組成。有些匯編命令出現(xiàn)在以 .c 為擴(kuò)展名的C 文件中,在這種文件中,既有C 語言,也有匯編語言,我們把出現(xiàn)在 C代碼中的匯編語言叫所“嵌入式”匯編。不管這些匯編代碼出現(xiàn)在哪里,它在一定程度上都成為閱讀源代碼的攔路虎。盡管 C語言已經(jīng)成為編寫操作系統(tǒng)的主要語言,但是,在操作系統(tǒng)與硬件打交道的過程中,在需要頻繁調(diào)用的函數(shù)中以及某些特殊的場合中,C語言顯得力不從心,這時,繁瑣但又高效的匯編語言必須粉墨登場。因此,在了解一些硬件的基礎(chǔ)上,
2、必須對相關(guān)的匯編語言知識也所有了解。讀者可能有過在DOS操作系統(tǒng)下編寫匯編程序的經(jīng)歷,也具備一定的匯編知識。但是,在 Linux 的源代碼中,你可能看到了與Intel的匯編語言格式不一樣的形式,這就是AT&T 的 386 匯編語言。一、 AT&T 與 Intel匯編語言的比較我們知道, Linux 是 Unix 家族的一員,盡管Linux 的歷史不長,但與其相關(guān)的很多事情都發(fā)源于Unix 。就 Linux 所使用的386 匯編語言而言,它也是起源于Unix 。Unix 最初是為 PDP 11開發(fā)的,曾先后被移植到VAX 及 68000 系列的處理器上,這些處理器上的匯編語言都采
3、用的是AT&T 的指令格式。當(dāng)Unix 被移植到i386 時,自然也就采用了AT&T 的匯編語言格式,而不是Intel的格式。盡管這兩種匯編語言在語法上有一定的差異,但所基于的硬件知識是相同的,因此,如果你非常熟悉Intel的語法格式,那么你也可以很容易地把它“移植“到AT&T 來。下面我們通過對照Intel與 AT&T 的語法格式,以便于你把過去的知識能很快地“移植”過來。1前綴在 Intel的語法中,寄存器和和立即數(shù)都沒有前綴。但是在AT&T 中,寄存器前冠以“”,而立即數(shù)前冠以“$” 。在 Intel的語法中,十六進(jìn)制和二進(jìn)制立即數(shù)后綴分別冠以“
4、h” 和“ b” ,而在 AT&T 中,十六進(jìn)制立即數(shù)前冠以“0x ”,表 2.2 給出幾個相應(yīng)的例子。表 2.2 Intel 與 AT&T 前綴的區(qū)別Intel語法AT&T 語法moveax,8movl$8,%eaxmovebx,0ffffhmovl$0xffff,%ebxint80hint$0x802. 操作數(shù)的方向Intel與 AT&T 操作數(shù)的方向正好相反。在Intel語法中,第一個操作數(shù)是目的操作數(shù),第二個操作數(shù)源操作數(shù)。而在 AT&T 中,第一個數(shù)是源操作數(shù),第二個數(shù)是目的操作數(shù)。由此可以看出,AT&T 的語法符合人們通常的閱讀習(xí)慣。
5、例如:在Intel中,moveax,ecx在AT&T 中, movl(%ecx),%eax3內(nèi)存單元操作數(shù)從上面的例子可以看出,內(nèi)存操作數(shù)也有所不同。在Intel的語法中,基寄存器用“”括起來,而在AT&T 中,用“()”括起來。例如:在Intel中, moveax,ebx+5在AT&T, movl5(%ebx),%eax4間接尋址方式與Intel的語法比較,AT&T 間接尋址方式可能更晦澀難懂一些。Intel的指令格式是segreg:base+index*scale+disp,而 AT&T 的格式是%segreg:disp(base,index,sca
6、le)。其中index/scale/disp/segreg全部是可選的,完全可以簡化掉 。如果沒有指定 scale 而指定了index ,則 scale 的缺省值 為 1。segreg 段寄存器 依賴 于指令以及應(yīng)用程序是運(yùn)行在實模式還是保護(hù)模 式下,在 實模 式下,它 依賴 于指令,而在保護(hù)模 式下, segreg是多 余的。在AT&T 中,當(dāng)立即數(shù)用在 scale/disp 中時,不應(yīng)當(dāng)在其前冠以“$” 前綴,表2.3 給出其語法及幾個相應(yīng)的例子。表 2.3內(nèi)存操作數(shù)的語法及舉例Intel 語法AT&T 語法指令foo,segreg:base+index*scale+dis
7、p指令%segreg:disp(base,index,scale),foomoveax,ebx+20hMovl0x20(%ebx),%eaxaddeax,ebx+ecx*2hAddl(%ebx,%ecx,0x2),%eaxleaeax,ebx+ecxLeal(%ebx,%ecx),%eaxsubeax,ebx+ecx*4h-20hSubl-0x20(%ebx,%ecx,0x4),%eax從表中可以看出,AT&T 的語法比較晦澀難懂,因為base+index*scale+disp一眼就可以看出其 含義 ,而 disp(base,index,scale)則不可能 做到這 點。這種尋址方式常
8、常用在訪問 數(shù)據(jù)結(jié)構(gòu) 數(shù)組中某個特定元素內(nèi)的一個字段,其中,base 為數(shù)組的起始地址, scale 為 每個數(shù)組元 素的大小 , index 為下 標(biāo)。如果數(shù)組元素還是一個 結(jié)構(gòu) ,則 disp 為具 體字 段在 結(jié)構(gòu) 中的 位移。5操作碼的后綴在上面的例子中你可能已注意 到,在AT&T 的操作碼后面有一個后綴,其含義 就是指出操作碼的大小 ?!?l ”表 示長整數(shù)( 32 位),“ w” 表示字 ( 16位),“ b” 表示字節(jié)( 8 位)。而在 Intel的語法中,則要在內(nèi)存單元操作數(shù)的前面加上 byte ptr、 word ptr,和 dword ptr ,“ dword ”對
9、應(yīng)“ long ”。表 2.4 給出幾個相應(yīng)的例子。表 2.4 操作碼的后綴 舉例Intel 語法AT&T 語法Moval,blmovb%bl,%alMovax,bxmovw%bx,%axMoveax,ebxmovl%ebx,%eaxMoveax, dword ptr ebxmovl(%ebx),%eax二、AT&T 匯編語言的相關(guān)知識在 Linux 源代碼中,以.S 為擴(kuò)展名的文件是“純 ”匯編語言的文件。這里,我們結(jié)合具體的例子 再介紹 一些 AT&T 匯編語言的相關(guān)知識。1 GNU匯編程序GAS( GNU Assembly 和連接程序當(dāng)你編寫了一個程序后,就需要對
10、其進(jìn)行匯編( assembly )和 連接。在 Linux 下有兩種方式,一種是使用匯編程序GAS和連接程序 ld ,一種是使用gcc 。我們先來看一下GAS和 ld:GAS把匯編語言源文件(.o) 轉(zhuǎn)換 為目 標(biāo)文件( .o),其基 本語法如下:as filename.s -o filename.o一旦創(chuàng)建 了一個目 標(biāo)文件,就需要把它連接并執(zhí)行 ,連接一個目 標(biāo)文件的基 本語法為:ld filename.o -o filename這里filename.o是目 標(biāo)文件名,而filename是輸出 (可執(zhí)行 ) 文件。GAS使用的是AT&T 的語法而不是Intel的語法,這就再次說明
11、了 AT&T 語法是Unix世界 的標(biāo)準(zhǔn) ,你必須熟悉它。如果要使用GNC的 C編譯器 gcc ,就可以一 步完成匯編和連接,例如:gcc -o example example.S這里, example.S 是你的匯編程序,輸出文件(可執(zhí)行 文件)名為example 。其中,擴(kuò)展名必須為大寫的 S,這是因為,令, 像 #include 、#define 、#ifdef匯編程序中使用C的預(yù)處理命令。大寫的 S可以使 gcc 自動識別匯編程序中的C預(yù)處理命、 #endif等,也就是 說,使用 gcc 進(jìn)行編譯,你可以在2. AT&T 中的 節(jié)( Section )在 AT&
12、T 的語法中,一個節(jié)由 .section關(guān)鍵詞 來 標(biāo)識,當(dāng)你編寫匯編語言程序時,至少需要有以下 三種節(jié):.section .data:這種 節(jié)包含 程序已初 始化 的數(shù) 據(jù),也就是說, 包含 具有初 值的那些 變量,例如:hello: .string "Hello world!n"hello_len : .long 13.section .bss:這個 節(jié)包含 程序 還未 初始化 的數(shù) 據(jù) ,也就是 說, 包含 沒有初 值的那些 變量。當(dāng)操作系統(tǒng)裝入這個程序時將把這些 變量 都置為 0,例如:name: .fill 30#用來 請求 用戶輸 入名 字name_len :
13、.long 0#名字的長度(尚未 定義 )當(dāng)這個程序被裝入時, name 和name_len 都被 置為 0。如果你在.bss 節(jié)不小心給一個變量賦 了初值,這個 值也會丟失 ,并且變量 的值仍為 0。使用 .bss 比使用 .data 的優(yōu)勢 在于, .bss 節(jié)不占用磁盤 的空間。在磁盤 上,一個長整數(shù)就足以存 放 .bss 節(jié) 。當(dāng)程序被 裝入到內(nèi)存時,操作系統(tǒng)也只分 配給這個 節(jié) 4 個字節(jié) 的內(nèi)存大小 。注意 :編 譯程序把 .data 和 .bss 在 4 字節(jié) 上對 齊( align ),例如, .data 總共 有 34 字節(jié),那么編 譯程序把它對其在36 字節(jié) 上,也就是說,
14、實際 給它 36 字節(jié) 的 空間。.section .text:這個 節(jié)包含 程序的代碼,它是只讀節(jié),而 .data和 .bss 是讀 寫節(jié)。3匯編程序指令(Assembler Directive)上面介紹 的 .section 就是匯編程序指令的一種,GNU匯編程序 提供 了很多這樣的指令( directiv),這種指令都是以句點 ( .)為開 頭,后 跟指令名( 小寫字母 ),在此,我們只介紹 在內(nèi) 核源代碼中出現(xiàn)的幾個指令(以arch/i386/kernel/head.S中的代碼為例)。( 1) ascii "string".ascii表示零個或多個(用 逗號隔 開)
15、字符串,并把每個字符串(結(jié)尾不自動加“ 0“ 字節(jié) )中的 字符放在連續(xù) 的地址單元。還有一個與 .ascii類似 的 .asciz , z 代表“ 0“ ,即 每個字符串結(jié)尾 自動加 一個” 0“字節(jié) ,例如:int_msg:.asciz "Unknown interruptn"( 2) .byte 表達(dá)式.byte 表示零或 多個表 達(dá)式(用 逗號隔 開), 每個表 達(dá) 式被 放在下一個 字節(jié) 單元。( 3) .fill表達(dá)式形式: .fill repeat , size , value其中,repeatsize和valueFill的含義 是反 復(fù)拷貝size個字節(jié) 。
16、、都是常 量表達(dá)式。Repeat 可以 大于等于 0。size也可以 大于等于 0,但不能超過 8,如果 超過 8,也 只取 8。把repeat個字節(jié) 以 8 個為一組, 每組的最高4 個字節(jié) 內(nèi)容為 0,最 低 4 字節(jié) 內(nèi)容 置為 value 。Size 和 value 為可選 項 。如果第二個逗號 和 value 值不存在, 則假 定 value 為 0。如果第一個 逗號 和 size 不存在, 則假 定 size 為 1。例如,在 Linux 初始化 的過程中,對全局描述 符表 GDT進(jìn)行設(shè)置 的最后一 句為:.fill NR_CPUS*4,8,0/* space for TSS
17、9;s and LDT's */因為每個描述 符正好 占 8 個字節(jié) ,因此, .fill給每個 CPU留有存 放 4 個描述 符的 位置。( 4) .globl symbol.globl使得 連接程序( ld )能 夠看到 symbl 。如果你的局部程序中定義了 symbl ,那么,與這個 局部程序 連接的其 他局 部程序也能存取 symbl ,例如:.globl SYMBOL_NAME(idt).globl SYMBOL_NAME(gdt)定義 idt和 gdt 為全 局 符號。( 5) quad bignums.quad 表示零 個或多個 bignums (用 逗號 分隔),對于
18、 每個 bignum ,其 缺省值 是 8 字節(jié)整數(shù)。如果bignum 超過 8 字節(jié) ,則打印 一個 警告信息;并只取bignum 最低 8 字節(jié) 。例如,對全 局描述 符表的 填充 就用到這個指令:.quad 0x00cf9a000000ffff/* 0x10 kernel 4GB code at 0x00000000 */.quad 0x00cf92000000ffff/* 0x18 kernel 4GB data at 0x00000000 */.quad 0x00cffa000000ffff/* 0x23 user4GB code at 0x00000000 */.quad 0x00
19、cff2000000ffff/* 0x2b user4GB data at 0x00000000 */( 6) rept count把.rept 指令與 .endr 指令 之間的 行重復(fù) count 次,例如.rept3.long0.endr相當(dāng)于.long0.long0.long0( 7) space size , fill這個指令 保留 size 個字節(jié) 的空間, 每個字節(jié) 的值為 fill。size和 fill都是常 量表達(dá)式。如果 逗號 和 fill被省略 ,則假 定 fill為 0,例如在arch/i386/bootl/setup.S中有一 句:.space 1024表示保留 102
20、4字節(jié)的空間,并且每 個字節(jié) 的值為 0。( 8) .word expressions這個表 達(dá)式表 示任意 一節(jié)中的一個 或多個表 達(dá)式(用 逗號 分開),表達(dá)式的 值占 兩個字節(jié) ,例如:gdt_descr:.word GDT_ENTRIES*8-1表示變量 gdt_descr 的置為 GDT_ENTRIES*8-1( 9) .long expressions這與.word 類似( 10) .org new-lc , fill把當(dāng)前節(jié)的位置計 數(shù)器 提前到 new-lc ( new location counter)。new-lc或者是一個常量表達(dá)式, 或者是一個與當(dāng)前子節(jié)處于同一 節(jié)的表
21、 達(dá) 式。也就是 說,你不能用 .org 橫跨節(jié):如果 new-lc是個 錯誤 的值,則 .org 被忽略 。.org 只能增加位置計 數(shù)器的 值,或者讓其保持 不變; 但絕不能用 .org 來讓位置計 數(shù)器 倒退 。注意 ,位置計 數(shù)器的起 始值 是相對于一個節(jié)的開 始的,而不是子節(jié)的開 始。當(dāng) 位置計數(shù)器被 提升 后,中間 位置 的 字節(jié) 被填充值fill(這也是一個常量表達(dá)式)。如果逗號 和fill都省略 ,則 fill的缺省值 為 0。例如: .org 0x2000ENTRY(pg0)表示把位置計 數(shù)器 置為 0x2000 ,這個 位置 存放的就是 臨時頁表 pg0。三、 Gcc 嵌入
22、式匯編在 Linux 的源代碼中,有很多C 語言的函數(shù)中嵌入一段匯編語言程序段,這就是gcc提供 的“ asm”功 能,例如在include/asm-i386/system.h中定 義的,讀 控制寄存器CR0的一個 宏 read_cr0() :)這種形式看起來比較陌生 ,這是因為這不是標(biāo)準(zhǔn) C所定 義的形式,而是gcc 對 C語言的擴(kuò) 充 。其中 _dummy為 C 函數(shù)所定 義的變量; 關(guān)鍵詞 _asm_表示匯編代碼的開始。括弧中第一個 引號 中為匯編指令 movl ,緊接著有一個 冒號 ,這種形式閱讀起來比較 復(fù)雜 。一般而言,嵌入式匯編語言片段比單 純的匯編語言代碼要 復(fù)雜 得多,因為這
23、里存在怎樣分 配和使用寄存器,以及把 C 代碼中的 變量 應(yīng)該存放在哪個寄存器中。 為了 達(dá)到這個目的,就必須對一般的 C 語言進(jìn) 行擴(kuò)充, 增加 對編 譯 器的指 導(dǎo) 作用,因此,嵌入式匯編看起來晦澀而難以讀懂。1. 嵌入式匯編的一 般形式:_asm_ _volatile_ ("<asm routine>" : output : input : modify);其中, _asm_表示匯編代碼的開始,其后可以跟 _volatile_(這是可選項),其含義 是避免 “ asm”指令被 刪除 、移 動或 組合 ;然后就是 小括弧,括 弧中的內(nèi)容是我們介紹的重點:
24、183;"<asm routine>"為匯編指令部分,例如,"movl %cr0,%0nt"。數(shù)字前加前綴“,如 1, 2 等表示使用寄存器的樣 板操作數(shù)。 可以使用的操作數(shù)總數(shù)取決于具體 CPU中通用寄存器的數(shù)量,如 Intel 可以有8 個。指令中有幾個操作數(shù),就說明 有幾個 變量需要與寄存器結(jié)合,由 gcc 在編 譯時根據(jù) 后面 輸出部分和 輸入部分的 約束條 件進(jìn)行相應(yīng)的處理。 由于這些樣 板操作數(shù)的前綴使用了”“,因此,在用到具體的寄存器時就在前面 加兩個“”,如 %cr0。·輸出部分( output ),用以 規(guī)定對 輸
25、 出變量 (目 標(biāo)操作數(shù))如 何與寄存器 結(jié)合的 約束( constraint ) ,輸出部分可以有多個約束,互相以逗號分開。每個約束以“ ”開頭,接 著用一個 字母 來表 示操作數(shù)的 類型 ,然后是關(guān)于 變量結(jié) 合的 約束 。例如,上例中::"=r" (_dummy)“ r ” 表示相應(yīng)的目 標(biāo)操作數(shù)(指令部分的%0)可以使用任何 一個通用寄存器,并且變量 _dummy 存放在這個寄存器中,但如果是:“ m” ( _dummy)“ m” 就表 示相應(yīng)的目 標(biāo)操作數(shù)是存放在內(nèi)存單元 _dummy中。表示約束條 件的 字母 很多,表2 5 給出幾個主要的約束字母 及其 含義
26、:表 2.5主要的 約束字母 及其 含義字母含義m, v,o表示內(nèi)存單元R表示任何 通用寄存器Q表示寄存器 eax, ebx, ecx,edx之一I, h表示直 接操作數(shù)E, F表示浮點 數(shù)G表示“任意 ”a, b.c d表示要求使用寄存器eax/ax/al, ebx/bx/bl, ecx/cx/cl或 edx/dx/dlS, D表示要求使用寄存器esi 或 ediI表示常數(shù)( 0 31)·輸入部分( Input ): 輸入部分與 輸出部分相 似 ,但沒有“ ”。如果 輸入部分一個操作數(shù)所要求使用的寄存器,與前面輸出部分某個約束 所要 求的是同一個寄存器,那就把對應(yīng)操作數(shù)的編號(如“
27、 1”,“ 2” 等) 放在約束條 件中,在后面的例子中我們 會看到這種情 況。·修改 部分( modify ) :這部分常常以“memory ”為 約束條 件,以表 示操作完成后內(nèi)存中的內(nèi)容已有改變 ,如果 原來某個寄存器的內(nèi)容來自內(nèi)存,那么現(xiàn)在內(nèi)存中這個單元的內(nèi)容已經(jīng)改變 。注意 ,指令部分為必選項,而 輸入部分、輸出部分及 修改 部分為可選 項,當(dāng) 輸入部分存在,而 輸 出部分不存在時,分號 “:“要 保留 ,當(dāng)“ memory ”存在時, 三個分 號都要 保留 ,例如 system.h 中的 宏定義 _cli():#define _cli()_asm_ _volatile_(
28、"cli": : :"memory")2. Linux 源代碼中嵌入式匯編 舉例Linux 源代碼中,在arch 目錄下的 .h 和 .c 文件中,很多文件都涉及嵌入式匯編,下面以 system.h 中的 C函數(shù)為例, 說明 嵌入式匯編的應(yīng)用。( 1)簡單應(yīng)用#define _save_flags(x)_asm_ _volatile_("pushfl ; popl %0":"=g" (x):/* no input */)#define _restore_flags(x)_asm_ _volatile_("
29、pushl %0 ; popfl": /* nooutput */:"g" (x):"memory", "cc")第一個 宏是 保存標(biāo)志 寄存器的 值,第二個 宏是 恢復(fù)標(biāo)志 寄存器的 值。第一個 宏中的pushfl指令是把 標(biāo)志 寄存器的 值壓棧 。而 popl 是把 棧頂 的值(剛壓 入棧的 flags )彈出到x 變量 中,這個 變量 可以存 放在一個寄存器或內(nèi)存中。這樣,你可以很容易地讀懂第二個宏。(2) 較復(fù)雜 應(yīng)用static inline unsigned long get_limit(unsigned lon
30、g segment)unsigned long _limit;_asm_("lsll %1,%0":"=r" (_limit):"r" (segment);return _limit+1;這是一個 設(shè)置 段界限 的函數(shù),匯編代碼段中的輸出參數(shù)為_limit%0(即 ),輸入?yún)?shù)為 segment(即 %1)。 Lsll 是加載 段界限 的指令,即把segment 段描述 符中的段 界限字段裝入某個寄存器(這個寄存器與_limit 結(jié)合),函數(shù)返回 _limit加 1,即段長。(3)復(fù)雜 應(yīng)用在 Linux 內(nèi) 核代碼中,有關(guān)字符串操作的函數(shù)都是通過嵌入式匯編完成的,因為內(nèi)核及用 戶程序?qū)?字符串函數(shù)的調(diào)用非常頻繁,因此,用匯編代碼實現(xiàn)主要是為了提高效率(當(dāng)然是以 犧牲 可讀 性和可 維護(hù)性 為代 價的)。在此,我們僅列舉一個 字符串比較函數(shù)strcmp ,其代碼在arch/i386 string.h中。static inline int strcmp(const char * cs,const char * ct)int d0, d1;register int _res;_asm_ _volatile_("1
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 光伏發(fā)電系統(tǒng)故障診斷與維護(hù)技術(shù)光伏組件熱斑故障分析考核試卷
- 冷凍飲品生產(chǎn)環(huán)境中的空氣質(zhì)量管理考核試卷
- 海鮮養(yǎng)殖面試題及答案
- 船舶輻射考試題及答案
- 防震減災(zāi)面試題及答案
- 三一技師考試試題及答案
- 老房改造測試題及答案
- 湖南省長沙市岳麓實驗中學(xué)2024-2025學(xué)年高一下學(xué)期6月月考數(shù)學(xué)試卷
- 2025屆上海市風(fēng)華中學(xué)高二化學(xué)第二學(xué)期期末學(xué)業(yè)質(zhì)量監(jiān)測試題含解析
- 數(shù)據(jù)分析基礎(chǔ)(第2版)課件 第4.2 描述性統(tǒng)計
- 年產(chǎn)5萬噸趣味酥性餅干生產(chǎn)車間設(shè)計
- RFJ013-2010 人民防空工程防化設(shè)計規(guī)范
- 柳州某醫(yī)院空氣源熱泵熱水系統(tǒng)設(shè)計案例
- 西師大版六年級數(shù)學(xué)下冊第四單元 扇形統(tǒng)計圖 單元概述和課時安排
- 高中英語全國高考考綱詞匯3600匯總
- 《中越傳統(tǒng)節(jié)日對比問題研究5100字【論文】》
- 特勞特戰(zhàn)略定位總裁課程課件
- 《 民航服務(wù)心理學(xué)》考試題及參考答案
- 2021學(xué)堂在線網(wǎng)課《生活英語讀寫》課后作業(yè)單元考核答案
- 中國近現(xiàn)代史綱要超星爾雅答案貴州大學(xué)-
- Q∕GDW 12162-2021 隔離開關(guān)分合閘位置雙確認(rèn)系統(tǒng)技術(shù)規(guī)范
評論
0/150
提交評論