匯編語言入門

學(xué)習(xí)編程其實(shí)就是學(xué)高級(jí)語言察净,即那些為人類設(shè)計(jì)的計(jì)算機(jī)語言。

但是盼樟,計(jì)算機(jī)不理解高級(jí)語言氢卡,必須通過編譯器轉(zhuǎn)成二進(jìn)制代碼,才能運(yùn)行晨缴。學(xué)會(huì)高級(jí)語言译秦,并不等于理解計(jì)算機(jī)實(shí)際的運(yùn)行步驟。

image

計(jì)算機(jī)真正能夠理解的是低級(jí)語言击碗,它專門用來控制硬件筑悴。匯編語言就是低級(jí)語言,直接描述/控制 CPU 的運(yùn)行稍途。如果你想了解 CPU 到底干了些什么阁吝,以及代碼的運(yùn)行步驟,就一定要學(xué)習(xí)匯編語言械拍。

匯編語言不容易學(xué)習(xí)突勇,就連簡明扼要的介紹都很難找到。下面我嘗試寫一篇最好懂的匯編語言教程坷虑,解釋 CPU 如何執(zhí)行代碼甲馋。

image

一、匯編語言是什么迄损?

我們知道定躏,CPU 只負(fù)責(zé)計(jì)算,本身不具備智能。你輸入一條指令(instruction)痊远,它就運(yùn)行一次绑谣,然后停下來,等待下一條指令拗引。

這些指令都是二進(jìn)制的,稱為操作碼(opcode)幌衣,比如加法指令就是00000011矾削。編譯器的作用,就是將高級(jí)語言寫好的程序豁护,翻譯成一條條操作碼哼凯。

對(duì)于人類來說,二進(jìn)制程序是不可讀的楚里,根本看不出來機(jī)器干了什么断部。為了解決可讀性的問題,以及偶爾的編輯需求班缎,就誕生了匯編語言蝴光。

image

匯編語言是二進(jìn)制指令的文本形式,與指令是一一對(duì)應(yīng)的關(guān)系达址。比如蔑祟,加法指令00000011寫成匯編語言就是 ADD。只要還原成二進(jìn)制,匯編語言就可以被 CPU 直接執(zhí)行,所以它是最底層的低級(jí)語言豺妓。

二冕香、來歷

最早的時(shí)候,編寫程序就是手寫二進(jìn)制指令芬位,然后通過各種開關(guān)輸入計(jì)算機(jī),比如要做加法了,就按一下加法開關(guān)篇亭。后來,發(fā)明了紙帶打孔機(jī)乳蛾,通過在紙帶上打孔暗赶,將二進(jìn)制指令自動(dòng)輸入計(jì)算機(jī)。

為了解決二進(jìn)制指令的可讀性問題肃叶,工程師將那些指令寫成了八進(jìn)制蹂随。二進(jìn)制轉(zhuǎn)八進(jìn)制是輕而易舉的,但是八進(jìn)制的可讀性也不行因惭。很自然地岳锁,最后還是用文字表達(dá),加法指令寫成 ADD蹦魔。內(nèi)存地址也不再直接引用激率,而是用標(biāo)簽表示咳燕。

這樣的話,就多出一個(gè)步驟乒躺,要把這些文字指令翻譯成二進(jìn)制招盲,這個(gè)步驟就稱為 assembling,完成這個(gè)步驟的程序就叫做 assembler嘉冒。它處理的文本曹货,自然就叫做 aseembly code。標(biāo)準(zhǔn)化以后讳推,稱為 assembly language顶籽,縮寫為 asm,中文譯為匯編語言银觅。

image

每一種 CPU 的機(jī)器指令都是不一樣的礼饱,因此對(duì)應(yīng)的匯編語言也不一樣。本文介紹的是目前最常見的 x86 匯編語言究驴,即 Intel 公司的 CPU 使用的那一種镊绪。

三、寄存器

學(xué)習(xí)匯編語言洒忧,首先必須了解兩個(gè)知識(shí)點(diǎn):寄存器和內(nèi)存模型镰吆。

先來看寄存器。CPU 本身只負(fù)責(zé)運(yùn)算跑慕,不負(fù)責(zé)儲(chǔ)存數(shù)據(jù)万皿。數(shù)據(jù)一般都儲(chǔ)存在內(nèi)存之中,CPU 要用的時(shí)候就去內(nèi)存讀寫數(shù)據(jù)核行。但是牢硅,CPU 的運(yùn)算速度遠(yuǎn)高于內(nèi)存的讀寫速度,為了避免被拖慢芝雪,CPU 都自帶一級(jí)緩存和二級(jí)緩存减余。基本上惩系,CPU 緩存可以看作是讀寫速度較快的內(nèi)存位岔。

但是,CPU 緩存還是不夠快堡牡,另外數(shù)據(jù)在緩存里面的地址是不固定的抒抬,CPU 每次讀寫都要尋址也會(huì)拖慢速度。因此晤柄,除了緩存之外擦剑,CPU 還自帶了寄存器(register),用來儲(chǔ)存最常用的數(shù)據(jù)。也就是說惠勒,那些最頻繁讀寫的數(shù)據(jù)(比如循環(huán)變量)赚抡,都會(huì)放在寄存器里面,CPU 優(yōu)先讀寫寄存器纠屋,再由寄存器跟內(nèi)存交換數(shù)據(jù)涂臣。

image

寄存器不依靠地址區(qū)分?jǐn)?shù)據(jù),而依靠名稱售担。每一個(gè)寄存器都有自己的名稱肉康,我們告訴 CPU 去具體的哪一個(gè)寄存器拿數(shù)據(jù),這樣的速度是最快的灼舍。有人比喻寄存器是 CPU 的零級(jí)緩存。

四涨薪、寄存器的種類

早期的 x86 CPU 只有8個(gè)寄存器骑素,而且每個(gè)都有不同的用途。現(xiàn)在的寄存器已經(jīng)有100多個(gè)了刚夺,都變成通用寄存器献丑,不特別指定用途了,但是早期寄存器的名字都被保存了下來侠姑。

EAX

EBX

ECX

EDX

EDI

ESI

EBP

ESP

上面這8個(gè)寄存器之中创橄,前面七個(gè)都是通用的。ESP 寄存器有特定用途莽红,保存當(dāng)前 Stack 的地址(詳見下一節(jié))妥畏。

image

我們常常看到** 32位 CPU安吁、64位 CPU 這樣的名稱醉蚁,其實(shí)指的就是寄存器的大小。32 位 CPU 的寄存器大小就是4個(gè)字節(jié)**鬼店。

五网棍、內(nèi)存模型:Heap

寄存器只能存放很少量的數(shù)據(jù),大多數(shù)時(shí)候妇智,CPU 要指揮寄存器滥玷,直接跟內(nèi)存交換數(shù)據(jù)。所以巍棱,除了寄存器惑畴,還必須了解內(nèi)存怎么儲(chǔ)存數(shù)據(jù)。

程序運(yùn)行的時(shí)候航徙,操作系統(tǒng)會(huì)給它分配一段內(nèi)存桨菜,用來儲(chǔ)存程序和運(yùn)行產(chǎn)生的數(shù)據(jù)。這段內(nèi)存有起始地址和結(jié)束地址,比如從0x1000到0x8000倒得,起始地址是較小的那個(gè)地址泻红,結(jié)束地址是較大的那個(gè)地址

image

程序運(yùn)行過程中霞掺,對(duì)于動(dòng)態(tài)的內(nèi)存占用請(qǐng)求(比如新建對(duì)象谊路,或者使用malloc命令),系統(tǒng)就會(huì)從預(yù)先分配好的那段內(nèi)存之中菩彬,劃出一部分給用戶缠劝,具體規(guī)則是從起始地址開始劃分(實(shí)際上,起始地址會(huì)有一段靜態(tài)數(shù)據(jù)骗灶,這里忽略)惨恭。舉例來說,用戶要求得到10個(gè)字節(jié)內(nèi)存耙旦,那么從起始地址0x1000開始給他分配脱羡,一直分配到地址0x100A,如果再要求得到22個(gè)字節(jié)免都,那么就分配到0x1020锉罐。

image

這種因?yàn)?strong>用戶主動(dòng)請(qǐng)求而劃分出來的內(nèi)存區(qū)域,叫做 Heap(堆)nn绕娘。它由起始地址開始脓规,從低位(地址)向高位(地址)增長。Heap 的一個(gè)重要特點(diǎn)就是不會(huì)自動(dòng)消失险领,必須手動(dòng)釋放侨舆,或者由垃圾回收機(jī)制來回收。

六绢陌、內(nèi)存模型:Stack

除了 Heap 以外态罪,其他的內(nèi)存占用叫做 Stack(棧)。簡單說下面,Stack 是由于函數(shù)運(yùn)行而臨時(shí)占用的內(nèi)存區(qū)域复颈。

image

請(qǐng)看下面的例子。

intmain(){int a=2;int b=3;}

上面代碼中沥割,系統(tǒng)開始執(zhí)行main函數(shù)時(shí)耗啦,會(huì)為它在內(nèi)存里面建立一個(gè)幀(frame),所有main的內(nèi)部變量(比如a和b)都保存在這個(gè)幀里面机杜。main函數(shù)執(zhí)行結(jié)束后帜讲,該幀就會(huì)被回收,釋放所有的內(nèi)部變量椒拗,不再占用空間似将。

image

如果函數(shù)內(nèi)部調(diào)用了其他函數(shù)获黔,會(huì)發(fā)生什么情況?

intmain(){int a=2;int b=3;returnadd_a_and_b(a,b);}

上面代碼中在验,main函數(shù)內(nèi)部調(diào)用了add_a_and_b函數(shù)玷氏。執(zhí)行到這一行的時(shí)候,系統(tǒng)也會(huì)為add_a_and_b新建一個(gè)幀腋舌,用來儲(chǔ)存它的內(nèi)部變量盏触。也就是說,此時(shí)同時(shí)存在兩個(gè)幀:main和add_a_and_b块饺。一般來說赞辩,調(diào)用棧有多少層,就有多少幀授艰。

image

等到add_a_and_b運(yùn)行結(jié)束辨嗽,它的幀就會(huì)被回收,系統(tǒng)會(huì)回到函數(shù)main剛才中斷執(zhí)行的地方淮腾,繼續(xù)往下執(zhí)行糟需。通過這種機(jī)制,就實(shí)現(xiàn)了函數(shù)的層層調(diào)用来破,并且每一層都能使用自己的本地變量。

所有的幀都存放在 Stack忘古,由于幀是一層層疊加的徘禁,所以 Stack 叫做棧。生成新的幀髓堪,叫做"入棧"送朱,英文是 push;棧的回收叫做"出棧"干旁,英文是 pop驶沼。Stack 的特點(diǎn)就是,最晚入棧的幀最早出棧(因?yàn)樽顑?nèi)層的函數(shù)調(diào)用争群,最先結(jié)束運(yùn)行)回怜,這就叫做"后進(jìn)先出"的數(shù)據(jù)結(jié)構(gòu)。每一次函數(shù)執(zhí)行結(jié)束换薄,就自動(dòng)釋放一個(gè)幀玉雾,所有函數(shù)執(zhí)行結(jié)束,整個(gè) Stack 就都釋放了轻要。

image
image

Stack 是由內(nèi)存區(qū)域的結(jié)束地址開始复旬,從高位(地址)向低位(地址)分配。比如冲泥,內(nèi)存區(qū)域的結(jié)束地址是0x8000驹碍,第一幀假定是16字節(jié)壁涎,那么下一次分配的地址就會(huì)從0x7FF0開始;第二幀假定需要64字節(jié)志秃,那么地址就會(huì)移動(dòng)到0x7FB0怔球。

image

七、CPU 指令

7.1 一個(gè)實(shí)例
了解寄存器和內(nèi)存模型以后洽损,就可以來看匯編語言到底是什么了庞溜。下面是一個(gè)簡單的程序example.c。

intadd_a_and_b(int a,int b){returna+b;}intmain(){returnadd_a_and_b(2,3);}

gcc 將這個(gè)程序轉(zhuǎn)成匯編語言碑定。

$ gcc-S example.c

上面的命令執(zhí)行以后流码,會(huì)生成一個(gè)文本文件example.s,里面就是匯編語言延刘,包含了幾十行指令漫试。這么說吧,一個(gè)高級(jí)語言的簡單操作碘赖,底層可能由幾個(gè)驾荣,甚至幾十個(gè) CPU 指令構(gòu)成。CPU 依次執(zhí)行這些指令普泡,完成這一步操作播掷。

example.s經(jīng)過簡化以后,大概是下面的樣子撼班。

_add_a_and_b:push%ebx mov%eax,[%esp+8]mov%ebx,[%esp+12]add%eax,%ebx pop%ebx ret _main:push3push2call _add_a_and_b add%esp,8ret

可以看到歧匈,原程序的兩個(gè)函數(shù)add_a_and_b和main,對(duì)應(yīng)兩個(gè)標(biāo)簽_add_a_and_b和_main砰嘁。每個(gè)標(biāo)簽里面是該函數(shù)所轉(zhuǎn)成的 CPU 運(yùn)行流程件炉。

每一行就是 CPU 執(zhí)行的一次操作。它又分成兩部分矮湘,就以其中一行為例斟冕。
push%ebx

這一行里面,push是 CPU 指令缅阳,%ebx是該指令要用到的運(yùn)算子磕蛇。一個(gè) CPU 指令可以有零個(gè)到多個(gè)運(yùn)算子。

下面我就一行一行講解這個(gè)匯編程序十办,建議讀者最好把這個(gè)程序孤里,在另一個(gè)窗口拷貝一份,省得閱讀的時(shí)候再把頁面滾動(dòng)上來橘洞。

7.2 push 指令

根據(jù)約定捌袜,程序從_main標(biāo)簽開始執(zhí)行,這時(shí)會(huì)在 Stack 上為main建立一個(gè)幀炸枣,并將 Stack 所指向的地址虏等,寫入 ESP 寄存器弄唧。后面如果有數(shù)據(jù)要寫入main這個(gè)幀,就會(huì)寫在 ESP 寄存器所保存的地址霍衫。

然后候引,開始執(zhí)行第一行代碼。

push 3

push指令用于將運(yùn)算子放入 Stack敦跌,這里就是將3寫入main這個(gè)幀澄干。

雖然看上去很簡單,push指令其實(shí)有一個(gè)前置操作柠傍。它會(huì)先取出 ESP 寄存器里面的地址麸俘,將其減去4個(gè)字節(jié),然后將新地址寫入 ESP 寄存器惧笛。使用減法是因?yàn)?Stack 從高位向低位發(fā)展从媚,4個(gè)字節(jié)則是因?yàn)?的類型是int,占用4個(gè)字節(jié)患整。得到新地址以后拜效, 3 就會(huì)寫入這個(gè)地址開始的四個(gè)字節(jié)。

push2

第二行也是一樣各谚,push指令將2寫入main這個(gè)幀紧憾,位置緊貼著前面寫入的3。這時(shí)昌渤,ESP 寄存器會(huì)再減去 4個(gè)字節(jié)(累計(jì)減去8)赴穗。

image

7.3 call 指令

第三行的call指令用來調(diào)用函數(shù)。

call _add_a_and_b

上面的代碼表示調(diào)用add_a_and_b函數(shù)愈涩。這時(shí)望抽,程序就會(huì)去找_add_a_and_b標(biāo)簽加矛,并為該函數(shù)建立一個(gè)新的幀履婉。

下面就開始執(zhí)行_add_a_and_b的代碼。

push%ebx

這一行表示將 EBX 寄存器里面的值斟览,寫入_add_a_and_b這個(gè)幀毁腿。這是因?yàn)楹竺嬉玫竭@個(gè)寄存器,就先把里面的值取出來苛茂,用完后再寫回去已烤。

這時(shí),push指令會(huì)再將 ESP 寄存器里面的地址減去4個(gè)字節(jié)(累計(jì)減去12)妓羊。

7.4 mov 指令

mov指令用于將一個(gè)值寫入某個(gè)寄存器胯究。

mov%eax,[%esp+8]

這一行代碼表示,先將 ESP 寄存器里面的地址加上8個(gè)字節(jié)躁绸,得到一個(gè)新的地址裕循,然后按照這個(gè)地址在 Stack 取出數(shù)據(jù)臣嚣。根據(jù)前面的步驟,可以推算出這里取出的是2剥哑,再將2寫入 EAX 寄存器硅则。

下一行代碼也是干同樣的事情。

mov%ebx,[%esp+12]

上面的代碼將 ESP 寄存器的值加12個(gè)字節(jié)株婴,再按照這個(gè)地址在 Stack 取出數(shù)據(jù)怎虫,這次取出的是3,將其寫入 EBX 寄存器困介。

7.5 add 指令

add指令用于將兩個(gè)運(yùn)算子相加大审,并將結(jié)果寫入第一個(gè)運(yùn)算子。

add%eax,%ebx

上面的代碼將 EAX 寄存器的值(即2)加上 EBX 寄存器的值(即3)逻翁,得到結(jié)果5饥努,再將這個(gè)結(jié)果寫入第一個(gè)運(yùn)算子 EAX 寄存器。

7.6 pop 指令

pop指令用于取出 Stack 最近一個(gè)寫入的值(即最低位地址的值)八回,并將這個(gè)值寫入運(yùn)算子指定的位置酷愧。

pop%ebx

上面的代碼表示,取出 Stack 最近寫入的值(即 EBX 寄存器的原始值)缠诅,再將這個(gè)值寫回 EBX 寄存器(因?yàn)榧臃ㄒ呀?jīng)做完了溶浴,EBX 寄存器用不到了)。

注意管引,pop指令還會(huì)將 ESP 寄存器里面的地址加4士败,即回收4個(gè)字節(jié)。

7.7 ret 指令

ret指令用于終止當(dāng)前函數(shù)的執(zhí)行褥伴,將運(yùn)行權(quán)交還給上層函數(shù)谅将。也就是,當(dāng)前函數(shù)的幀將被回收重慢。

ret

可以看到饥臂,該指令沒有運(yùn)算子。

隨著add_a_and_b函數(shù)終止執(zhí)行似踱,系統(tǒng)就回到剛才main函數(shù)中斷的地方隅熙,繼續(xù)往下執(zhí)行。

add%esp,8

上面的代碼表示核芽,將 ESP 寄存器里面的地址囚戚,手動(dòng)加上8個(gè)字節(jié),再寫回 ESP 寄存器轧简。這是因?yàn)?ESP 寄存器的是 Stack 的寫入開始地址驰坊,前面的pop操作已經(jīng)回收了4個(gè)字節(jié),這里再回收8個(gè)字節(jié)哮独,等于全部回收拳芙。

ret

最后假勿,main函數(shù)運(yùn)行結(jié)束,ret指令退出程序執(zhí)行态鳖。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末转培,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子浆竭,更是在濱河造成了極大的恐慌浸须,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件邦泄,死亡現(xiàn)場離奇詭異删窒,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)顺囊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門肌索,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人特碳,你說我怎么就攤上這事诚亚。” “怎么了午乓?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵站宗,是天一觀的道長。 經(jīng)常有香客問我益愈,道長梢灭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任蒸其,我火速辦了婚禮敏释,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘摸袁。我一直安慰自己钥顽,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布但惶。 她就那樣靜靜地躺著耳鸯,像睡著了一般湿蛔。 火紅的嫁衣襯著肌膚如雪膀曾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天阳啥,我揣著相機(jī)與錄音添谊,去河邊找鬼。 笑死察迟,一個(gè)胖子當(dāng)著我的面吹牛斩狱,可吹牛的內(nèi)容都是我干的耳高。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼所踊,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼泌枪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起秕岛,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤碌燕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后继薛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體修壕,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年遏考,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了慈鸠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡灌具,死狀恐怖青团,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情咖楣,我是刑警寧澤壶冒,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站截歉,受9級(jí)特大地震影響胖腾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瘪松,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一咸作、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧宵睦,春花似錦记罚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至烟馅,卻和暖如春说庭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背郑趁。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來泰國打工刊驴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓捆憎,卻偏偏與公主長得像舅柜,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子躲惰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 1.地址總線致份,數(shù)據(jù)總線,控制總線在哪里础拨,它們有什么作用?答:它們都是cpu連接外部組件的線路知举。地址總線:地址總線A...
    MagicalGuy閱讀 1,437評(píng)論 0 1
  • 大家好,這是我在簡書發(fā)布的第一篇文章太伊,程序員學(xué)習(xí)一門語言一般都以HelloWorld開始雇锡,所以本篇以匯編語言的He...
    GeekLearning閱讀 1,577評(píng)論 0 2
  • 匯編基礎(chǔ)教程 16位和32位的80x86匯編語言的區(qū)別 需要注意的是匯編不是一種語言,不同平臺(tái)有不同的匯編語言對(duì)應(yīng)...
    inwunwe閱讀 9,487評(píng)論 2 19
  • 詳情請(qǐng)見: http://heamon7.gitbooks.io/cscw2-newly-to-assembly/...
    heamon7閱讀 10,194評(píng)論 0 24
  • 春心初動(dòng)生死劫僚焦,左腕紅痣招靈邪锰提。 鬼帝使者驚又現(xiàn),魂入丹田正陰結(jié)芳悲。 云禪大師剛剛給我安排好房間立肘,我的肚子就嘰里咕嚕...
    青龍先生詩詞社閱讀 404評(píng)論 0 3