【ARM 匯編基礎(chǔ)速成4】ARM匯編內(nèi)存訪(fǎng)問(wèn)相關(guān)指令

原文鏈接 https://azeria-labs.com/memory-instructions-load-and-store-part-4/

ARM使用加載-存儲(chǔ)模式控制對(duì)內(nèi)存的訪(fǎng)問(wèn)西傀,這意味著只有加載/存儲(chǔ)(LDR或者STR)才能訪(fǎng)問(wèn)內(nèi)存若贮。盡管X86中允許很多指令直接操作在內(nèi)存中的數(shù)據(jù)株搔,但ARM中依然要求在操作數(shù)據(jù)前,必須先從內(nèi)存中將數(shù)據(jù)取出來(lái)撞反。這就意味著如果要增加一個(gè)32位的在內(nèi)存中的值纪挎,需要做三種類(lèi)型的操作(加載已脓,加一艘儒,存儲(chǔ))將數(shù)據(jù)從內(nèi)存中取到寄存器,對(duì)寄存器中的值加一涮俄,再將結(jié)果放回到內(nèi)存中蛉拙。

為了解釋ARM架構(gòu)中的加載和存儲(chǔ)機(jī)制,我們準(zhǔn)備了一個(gè)基礎(chǔ)的例子以及附加在這個(gè)基礎(chǔ)例子上的三種不同的對(duì)內(nèi)存地址的便宜訪(fǎng)問(wèn)形式彻亲。每個(gè)例子除了STR/LDR的偏移模式不同外孕锄,其余的都一樣吮廉。而且這個(gè)例子很簡(jiǎn)單,最佳的實(shí)踐方式是用GDB去調(diào)試這段匯編代碼畸肆。

第一種偏移形式:立即數(shù)作為偏移

  • 地址模式:用作偏移
  • 地址模式:前向索引
  • 地址模式:后向索引

第二種偏移形式:寄存器作為偏移

  • 地址模式:用作偏移
  • 地址模式:前向索引
  • 地址模式:后向索引

第三種偏移形式:寄存器縮放值作為偏移

  • 地址模式:用作偏移
  • 地址模式:前向索引
  • 地址模式:后向索引

基礎(chǔ)樣例代碼

通常宦芦,LDR被用來(lái)從內(nèi)存中加載數(shù)據(jù)到寄存器,STR被用作將寄存器的值存放到內(nèi)存中恼除。

image
LDR R2, [R0]   @ [R0] - 數(shù)據(jù)源地址來(lái)自于R0指向的內(nèi)存地址
@ LDR操作:從R0指向的地址中取值放到R2中

STR R2, [R1]   @ [R1] - 目的地址來(lái)自于R1在內(nèi)存中指向的地址
@ STR操作:將R2中的值放到R1指向的地址中

樣例程序的匯編代碼及解釋如下:

.data          /* 數(shù)據(jù)段是在內(nèi)存中動(dòng)態(tài)創(chuàng)建的,所以它的在內(nèi)存中的地址不可預(yù)測(cè)*/
var1: .word 3  /* 內(nèi)存中的第一個(gè)變量 */
var2: .word 4  /* 內(nèi)存中的第二個(gè)變量 */

.text          /* 代碼段開(kāi)始 */ 
.global _start

_start:
    ldr r0, adr_var1  @ 將存放var1值的地址adr_var1加載到寄存器R0中 
    ldr r1, adr_var2  @ 將存放var2值的地址adr_var2加載到寄存器R1中 
    ldr r2, [r0]      @ 將R0所指向地址中存放的0x3加載到寄存器R2中  
    str r2, [r1]      @ 將R2中的值0x3存放到R1做指向的地址 
    bkpt             

adr_var1: .word var1  /* var1的地址助記符 */
adr_var2: .word var2  /* var2的地址助記符 */

在底部我們有我們的文字標(biāo)識(shí)池(在代碼段中用來(lái)存儲(chǔ)常量曼氛,字符串豁辉,或者偏移等的內(nèi)存,可以通過(guò)位置無(wú)關(guān)的方式引用)舀患,分別用adr_var1和adr_var2存儲(chǔ)著變量var1和var2的內(nèi)存地址(var1和var2的值在數(shù)據(jù)段定義)徽级。第一條LDR指令將變量var1的地址加載到寄存器R0。第二條LDR指令同樣將var2的地址加載到寄存器R1聊浅。之后我們將存儲(chǔ)在R0指向的內(nèi)存地址中的值加載到R2餐抢,最后將R2中的值存儲(chǔ)到R1指向的內(nèi)存地址中。

當(dāng)我們加載數(shù)據(jù)到寄存器時(shí)低匙,方括號(hào)“[]”意味著:將其中的值當(dāng)做內(nèi)存地址旷痕,并取這個(gè)內(nèi)存地址中的值加載到對(duì)應(yīng)寄存器。

當(dāng)我們存儲(chǔ)數(shù)據(jù)到內(nèi)存時(shí)顽冶,方括號(hào)“[]”意味著:將其中的值當(dāng)做內(nèi)存地址欺抗,并向這個(gè)內(nèi)存地址所指向的位置存入對(duì)應(yīng)的值。

聽(tīng)者好像有些抽象强重,所以再來(lái)看看這個(gè)動(dòng)畫(huà)吧:

image

同樣的再來(lái)看看的這段代碼在調(diào)試器中的樣子绞呈。

gef> disassemble _start
Dump of assembler code for function _start:
 0x00008074 <+0>:      ldr  r0, [pc, #12]   ; 0x8088 <adr_var1>
 0x00008078 <+4>:      ldr  r1, [pc, #12]   ; 0x808c <adr_var2>
 0x0000807c <+8>:      ldr  r2, [r0]
 0x00008080 <+12>:     str  r2, [r1]
 0x00008084 <+16>:     bx   lr
End of assembler dump.

可以看到此時(shí)的反匯編代碼和我們編寫(xiě)的匯編代碼有出入了。前兩個(gè)LDR操作的源寄存器被改成了[pc,#12]间景。這種操作叫做PC相對(duì)地址佃声。因?yàn)槲覀冊(cè)趨R編代碼中使用的只是數(shù)據(jù)的標(biāo)簽,所以在編譯時(shí)候編譯器幫我們計(jì)算出來(lái)了與我們想訪(fǎng)問(wèn)的文字標(biāo)識(shí)池的相對(duì)便宜倘要,即PC+12圾亏。你也可以看匯編代碼中手動(dòng)計(jì)算驗(yàn)證這個(gè)偏移是正確的,以adr_var1為例封拧,執(zhí)行到8074時(shí)召嘶,其當(dāng)前有效PC與數(shù)據(jù)段還有三個(gè)四字節(jié)的距離,所以要加12哮缺。關(guān)于PC相對(duì)取址我們接下來(lái)還會(huì)接著介紹弄跌。

PS:如果你對(duì)這里的PC的地址有疑問(wèn),可以看外面第二篇關(guān)于程序執(zhí)行時(shí)PC的值的說(shuō)明尝苇,PC是指向當(dāng)前執(zhí)行指令之后第二條指令所在位置的铛只,在32位ARM模式下是當(dāng)前執(zhí)行位置加偏移值8埠胖,在Thumb模式下是加偏移值4。這也是與X86架構(gòu)PC的區(qū)別之所在淳玩。

image

第一種偏移形式:立即數(shù)作偏移

STR    Ra, [Rb, imm]
LDR    Ra, [Rc, imm]

在這段匯編代碼中直撤,我們使用立即數(shù)作為偏移量。這個(gè)立即數(shù)被用來(lái)與一個(gè)寄存器中存放的地址做加減操作(下面例子中的R1)蜕着,以訪(fǎng)問(wèn)對(duì)應(yīng)地址偏移處的數(shù)據(jù)谋竖。

.data
var1: .word 3
var2: .word 4

.text
.global _start

_start:
    ldr r0, adr_var1  @ 將存放var1值的地址adr_var1加載到寄存器R0中 
    ldr r1, adr_var2  @ 將存放var2值的地址adr_var2加載到寄存器R1中 
    ldr r2, [r0]      @ 將R0所指向地址中存放的0x3加載到寄存器R2中  
    str r2, [r1, #2]  @ 取址模式:基于偏移量。R2寄存器中的值0x3被存放到R1寄存器的值加2所指向地址處承匣。
    str r2, [r1, #4]! @ 取址模式:基于索引前置修改蓖乘。R2寄存器中的值0x3被存放到R1寄存器的值加4所指向地址處,之后R1寄存器中存儲(chǔ)的值加4,也就是R1=R1+4韧骗。
    ldr r3, [r1], #4  @ 取址模式:基于索引后置修改嘉抒。R3寄存器中的值是從R1寄存器的值所指向的地址中加載的,加載之后R1寄存器中存儲(chǔ)的值加4,也就是R1=R1+4袍暴。
    bkpt

adr_var1: .word var1
adr_var2: .word var2

讓我們把上面的這段匯編代碼編譯一下些侍,并用GDB調(diào)試起來(lái)看看真實(shí)情況。

$ as ldr.s -o ldr.o
$ ld ldr.o -o ldr
$ gdb ldr

在GDB(使用GEF插件)中政模,我們對(duì)_start下一個(gè)斷點(diǎn)并繼續(xù)運(yùn)行程序岗宣。

gef> break _start
gef> run
...
gef> nexti 3     /* 向后執(zhí)行三條指令 */

執(zhí)行完上述GDB指令后,在我的系統(tǒng)的寄存器的值現(xiàn)在是這個(gè)樣子(在你的系統(tǒng)里面可能不同):

$r0 : 0x00010098 -> 0x00000003
$r1 : 0x0001009c -> 0x00000004
$r2 : 0x00000003
$r3 : 0x00000000
$r4 : 0x00000000
$r5 : 0x00000000
$r6 : 0x00000000
$r7 : 0x00000000
$r8 : 0x00000000
$r9 : 0x00000000
$r10 : 0x00000000
$r11 : 0x00000000
$r12 : 0x00000000
$sp : 0xbefff7e0 -> 0x00000001
$lr : 0x00000000
$pc : 0x00010080 -> <_start+12> str r2, [r1]
$cpsr : 0x00000010

下面來(lái)分別調(diào)試這三條關(guān)鍵指令淋样。首先執(zhí)行基于地址偏移的取址模式的STR操作了狈定。就會(huì)將R2(0x00000003)中的值存放到R1(0x0001009c)所指向地址偏移2的位置0x1009e。下面一段是執(zhí)行完對(duì)應(yīng)STR操作后對(duì)應(yīng)內(nèi)存位置的值习蓬。

gef> nexti
gef> x/w 0x1009e 
0x1009e <var2+2>: 0x3

下一條STR操作使用了基于索引前置修改的取址模式纽什。這種模式的識(shí)別特征是(!)。區(qū)別是在R2中的值被存放到對(duì)應(yīng)地址躲叼,R1的值也會(huì)被更新芦缰。這意味著,當(dāng)我們將R2中的值0x3存儲(chǔ)到R1(0x1009c)的偏移4之后的地址0x100A0后枫慷,R1的值也會(huì)被更新到為這個(gè)地址让蕾。下面一段是執(zhí)行完對(duì)應(yīng)STR操作后對(duì)應(yīng)內(nèi)存位置以及寄存器的值。

gef> nexti
gef> x/w 0x100A0
0x100a0: 0x3
gef> info register r1
r1     0x100a0     65696

最后一個(gè)LDR操作使用了基于索引后置的取址模式或听。這意味著基礎(chǔ)寄存器R1被用作加載的內(nèi)存地址探孝,之后R1的值被更新為R1+4。換句話(huà)說(shuō)誉裆,加載的是R1所指向的地址而不是R1+4所指向的地址顿颅,也就是0x100A0中的值被加載到R3寄存器,然后R1寄存器的值被更新為0x100A0+0x4也就是0x100A4足丢。下面一段是執(zhí)行完對(duì)應(yīng)LDR操作后對(duì)應(yīng)內(nèi)存位置以及寄存器的值粱腻。

gef> info register r1
r1      0x100a4   65700
gef> info register r3
r3      0x3       3

下圖是這個(gè)操作發(fā)生的動(dòng)態(tài)示意圖庇配。

image

第二種偏移形式:寄存器作偏移

STR    Ra, [Rb, Rc]
LDR    Ra, [Rb, Rc]

在這個(gè)偏移模式中,寄存器的值被用作偏移绍些。下面的樣例代碼展示了當(dāng)試著訪(fǎng)問(wèn)數(shù)組的時(shí)候是如何計(jì)算索引值的捞慌。

.data
var1: .word 3
var2: .word 4

.text
.global _start

_start:
    ldr r0, adr_var1  @ 將存放var1值的地址adr_var1加載到寄存器R0中 
    ldr r1, adr_var2  @ 將存放var2值的地址adr_var2加載到寄存器R1中 
    ldr r2, [r0]      @ 將R0所指向地址中存放的0x3加載到寄存器R2中  
    str r2, [r1, r2]  @ 取址模式:基于偏移量。R2寄存器中的值0x3被存放到R1寄存器的值加R2寄存器的值所指向地址處柬批。R1寄存器不會(huì)被修改啸澡。 
    str r2, [r1, r2]! @ 取址模式:基于索引前置修改。R2寄存器中的值0x3被存放到R1寄存器的值加R2寄存器的值所指向地址處氮帐,之后R1寄存器中的值被更新,也就是R1=R1+R2嗅虏。
    ldr r3, [r1], r2  @ 取址模式:基于索引后置修改。R3寄存器中的值是從R1寄存器的值所指向的地址中加載的揪漩,加載之后R1寄存器中的值被更新也就是R1=R1+R2旋恼。
    bx lr

adr_var1: .word var1
adr_var2: .word var2

下面來(lái)分別調(diào)試這三條關(guān)鍵指令吏口。在執(zhí)行完基于偏移量的取址模式的STR操作后奄容,R2的值被存在了地址0x1009c + 0x3 = 0x1009F處。下面一段是執(zhí)行完對(duì)應(yīng)STR操作后對(duì)應(yīng)內(nèi)存位置的值产徊。

gef> x/w 0x0001009F
 0x1009f <var2+3>: 0x00000003

下一條STR操作使用了基于索引前置修改的取址模式昂勒,R1的值被更新為R1+R2的值。下面一段是執(zhí)行完對(duì)應(yīng)STR操作后寄存器的值舟铜。

gef> info register r1
 r1     0x1009f      65695

最后一個(gè)LDR操作使用了基于索引后置的取址模式戈盈。將R1指向的值加載到R2之后,更新了R1寄存器的值(R1+R2 = 0x1009f + 0x3 = 0x100a2)谆刨。下面一段是執(zhí)行完對(duì)應(yīng)LDR操作后對(duì)應(yīng)內(nèi)存位置以及寄存器的值塘娶。

gef> info register r1
 r1      0x100a2     65698
gef> info register r3
 r3      0x3       3

下圖是這個(gè)操作發(fā)生的動(dòng)態(tài)示意圖。

image

第三種偏移形式:寄存器縮放值作偏移

LDR    Ra, [Rb, Rc, <shifter>]
STR    Ra, [Rb, Rc, <shifter>]

在這種偏移形式下痊夭,第三個(gè)偏移量還有一個(gè)寄存器做支持刁岸。Rb是基址寄存器,Rc中的值作為偏移量她我,或者是要被左移或右移的<shifter>次的值虹曙。這意味著移位器shifter被用來(lái)用作縮放Rc寄存器中存放的偏移量。下面的樣例代碼展示了對(duì)一個(gè)數(shù)組的循環(huán)操作番舆。同樣的酝碳,我們也會(huì)用GDB調(diào)試這段代碼。

.data
var1: .word 3
var2: .word 4

.text
.global _start

_start:
    ldr r0, adr_var1         @ 將存放var1值的地址adr_var1加載到寄存器R0中 
    ldr r1, adr_var2         @ 將存放var2值的地址adr_var2加載到寄存器R1中 
    ldr r2, [r0]             @ 將R0所指向地址中存放的0x3加載到寄存器R2中  
    str r2, [r1, r2, LSL#2]  @ 取址模式:基于偏移量恨狈。R2寄存器中的值0x3被存放到R1寄存器的值加(左移兩位后的R2寄存器的值)所指向地址處疏哗。R1寄存器不會(huì)被修改。
    str r2, [r1, r2, LSL#2]! @ 取址模式:基于索引前置修改禾怠。R2寄存器中的值0x3被存放到R1寄存器的值加(左移兩位后的R2寄存器的值)所指向地址處沃斤,之后R1寄存器中的值被更新,也就R1 = R1 + R2<<2圣蝎。
    ldr r3, [r1], r2, LSL#2  @ 取址模式:基于索引后置修改。R3寄存器中的值是從R1寄存器的值所指向的地址中加載的衡瓶,加載之后R1寄存器中的值被更新也就是R1 = R1 + R2<<2徘公。
    bkpt

adr_var1: .word var1
adr_var2: .word var2

下面來(lái)分別調(diào)試這三條關(guān)鍵指令。在執(zhí)行完基于偏移量的取址模式的STR操作后哮针,R2被存儲(chǔ)到的位置是[r1,r2,LSL#2]关面,也就是說(shuō)被存儲(chǔ)到R1+(R2<<2)的位置了,如下圖所示十厢。

image

下一條STR操作使用了基于索引前置修改的取址模式等太,R1的值被更新為R1+(R2<<2)的值。下面一段是執(zhí)行完對(duì)應(yīng)STR操作后寄存器的值蛮放。

gef> info register r1
r1      0x100a8      65704

最后一個(gè)LDR操作使用了基于索引后置的取址模式缩抡。將R1指向的值加載到R2之后,更新了R1寄存器的值(R1+R2 = 0x100a8 + (0x3<<2) = 0x100b4)包颁。下面一段是執(zhí)行完對(duì)應(yīng)LDR操作后寄存器的值瞻想。

gef> info register r1
r1      0x100b4      65716

小結(jié)

LDR/STR的三種偏移模式:

  1. 立即數(shù)作為偏移
ldr   r3, [r1, #4]
  1. 寄存器作為偏移
ldr   r3, [r1, r2]
  1. 寄存器縮放值作為偏移
ldr   r3, [r1, r2, LSL#2]

如何區(qū)分取址模式:

  1. 如果有一個(gè)嘆號(hào)!,那就是索引前置取址模式娩嚼,即使用計(jì)算后的地址蘑险,之后更新基址寄存器。
ldr   r3, [r1, #4]!
ldr   r3, [r1, r2]!
ldr   r3, [r1, r2, LSL#2]!
  1. 如果在[]外有一個(gè)寄存器岳悟,那就是索引后置取址模式佃迄,即使用原有基址寄存器重的地址,之后再更新基址寄存器
ldr   r3, [r1], #4
ldr   r3, [r1], r2
ldr   r3, [r1], r2, LSL#2
  1. 除此之外贵少,就都是偏移取址模式了
ldr   r3, [r1, #4]
ldr   r3, [r1, r2]
ldr   r3, [r1, r2, LSL#2]
  • 地址模式:用作偏移
  • 地址模式:前向索引
  • 地址模式:后向索引

關(guān)于PC相對(duì)取址的LDR指令

有時(shí)候LDR并不僅僅被用來(lái)從內(nèi)存中加載數(shù)據(jù)呵俏。還有如下這操作:

.section .text
.global _start

_start:
   ldr r0, =jump        /* 加載jump標(biāo)簽所在的內(nèi)存位置到R0 */
   ldr r1, =0x68DB00AD  /* 加載立即數(shù)0x68DB00AD到R1 */
jump:
   ldr r2, =511         /* 加載立即數(shù)511到R2 */ 
   bkpt

這些指令學(xué)術(shù)上被稱(chēng)作偽指令。但我們?cè)诰帉?xiě)ARM匯編時(shí)可以用這種格式的指令去引用我們文字標(biāo)識(shí)池中的數(shù)據(jù)滔灶。在上面的例子中我們用一條指令將一個(gè)32位的常量值放到了一個(gè)寄存器中普碎。為什么我們會(huì)這么寫(xiě)是因?yàn)锳RM每次僅僅能加載8位的值,原因傾聽(tīng)我解釋立即數(shù)在A(yíng)RM架構(gòu)下的處理宽气。

在A(yíng)RM中使用立即數(shù)的規(guī)律

是的随常,在A(yíng)RM中不能像X86那樣直接將立即數(shù)加載到寄存器中。因?yàn)槟闶褂玫牧⒓磾?shù)是受限的萄涯。這些限制聽(tīng)上去有些無(wú)聊绪氛。但是聽(tīng)我說(shuō),這也是為了告訴你繞過(guò)這些限制的技巧(通過(guò)LDR)涝影。

我們都知道每條ARM指令的寬度是32位枣察,所有的指令都是可以條件執(zhí)行的。我們有16中條件可以使用而且每個(gè)條件在機(jī)器碼中的占位都是4位。之后我們需要2位來(lái)做為目的寄存器序目。2位作為第一操作寄存器臂痕,1位用作設(shè)置狀態(tài)的標(biāo)記位,再加上比如操作碼(opcode)這些的占位猿涨。最后每條指令留給我們存放立即數(shù)的空間只有12位寬握童。也就是4096個(gè)不同的值。

這也就意味著ARM在使用MOV指令時(shí)所能操作的立即數(shù)值范圍是有限的叛赚。那如果很大的話(huà)澡绩,只能拆分成多個(gè)部分外加移位操作拼接了。

所以這剩下的12位可以再次劃分俺附,8位用作加載0-255中的任意值肥卡,4位用作對(duì)這個(gè)值做0~30位的循環(huán)右移。這也就意味著這個(gè)立即數(shù)可以通過(guò)這個(gè)公式得到:v = n ror 2*r事镣。換句話(huà)說(shuō)步鉴,有效的立即數(shù)都可以通過(guò)循環(huán)右移來(lái)得到。這里有一個(gè)例子

有效值:
#256        // 1 循環(huán)右移 24位 --> 256
#384        // 6 循環(huán)右移 26位 --> 384
#484        // 121 循環(huán)右移 30位 --> 484
#16384      // 1 循環(huán)右移 18位 --> 16384
#2030043136 // 121 循環(huán)右移 8位 --> 2030043136
#0x06000000 // 6 循環(huán)右移 8位 --> 100663296 (十六進(jìn)制值0x06000000)

Invalid values:
#370        // 185 循環(huán)右移 31位 --> 31不在范圍內(nèi) (0 – 30)
#511        // 1 1111 1111 --> 比特模型不符合
#0x06010000 // 1 1000 0001.. --> 比特模型不符合

看上去這樣并不能一次性加載所有的32位值璃哟。不過(guò)我們可以通過(guò)以下的兩個(gè)選項(xiàng)來(lái)解決這個(gè)問(wèn)題:

  1. 用小部分去組成更大的值玷禽。
    1. 比如對(duì)于指令 MOV r0, #511
    2. 將511分成兩部分:MOV r0, #256, and ADD r0, #255
  2. 用加載指令構(gòu)造‘ldr r1,=value’的形式魁袜,編譯器會(huì)幫你轉(zhuǎn)換成MOV的形式绑榴,如果失敗的話(huà)就轉(zhuǎn)換成從數(shù)據(jù)段中通過(guò)PC相對(duì)偏移加載怒医。
    1. LDR r1, =511

如果你嘗試加載一個(gè)非法的值熊响,編譯器會(huì)報(bào)錯(cuò)并且告訴你:Error: invalid constant匹表。如果在遇到這個(gè)問(wèn)題冀瓦,你現(xiàn)在應(yīng)該知道該怎么解決了吧缚窿。唉還是舉個(gè)栗子调鲸,就比如你想把511加載到R0盛杰。

.section .text
.global _start

_start:
    mov     r0, #511
    bkpt

這樣做的結(jié)果就是編譯報(bào)錯(cuò):

azeria@labs:~$ as test.s -o test.o
test.s: Assembler messages:
test.s:5: Error: invalid constant (1ff) after fixup

你需要將511分成多部分,或者直接用LDR指令藐石。

.section .text
.global _start

_start:
 mov r0, #256   /* 1 ror 24 = 256, so it's valid */
 add r0, #255   /* 255 ror 0 = 255, valid. r0 = 256 + 255 = 511 */
 ldr r1, =511   /* load 511 from the literal pool using LDR */
 bkpt

如果你想知道你能用的立即數(shù)的有效值即供,你不需要自己計(jì)算。我這有個(gè)小腳本于微,看你骨骼驚奇逗嫡,傳給你呦 rotator.py。用法如下株依。

azeria@labs:~$ python rotator.py
Enter the value you want to check: 511

Sorry, 511 cannot be used as an immediate number and has to be split.

azeria@labs:~$ python rotator.py
Enter the value you want to check: 256

The number 256 can be used as a valid immediate number.
1 ror 24 --> 256

譯者注:這作者真的是用心良苦驱证,我都看累了,但是怎么說(shuō)恋腕,反復(fù)練習(xí)加實(shí)踐抹锄,總歸是有好處的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市伙单,隨后出現(xiàn)的幾起案子获高,更是在濱河造成了極大的恐慌,老刑警劉巖吻育,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件念秧,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡布疼,警方通過(guò)查閱死者的電腦和手機(jī)出爹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)缎除,“玉大人严就,你說(shuō)我怎么就攤上這事∑鞴蓿” “怎么了梢为?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)轰坊。 經(jīng)常有香客問(wèn)我铸董,道長(zhǎng),這世上最難降的妖魔是什么肴沫? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任粟害,我火速辦了婚禮,結(jié)果婚禮上颤芬,老公的妹妹穿的比我還像新娘悲幅。我一直安慰自己,他們只是感情好站蝠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布汰具。 她就那樣靜靜地躺著,像睡著了一般菱魔。 火紅的嫁衣襯著肌膚如雪留荔。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,679評(píng)論 1 305
  • 那天澜倦,我揣著相機(jī)與錄音聚蝶,去河邊找鬼。 笑死藻治,一個(gè)胖子當(dāng)著我的面吹牛碘勉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播栋艳,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼恰聘,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起晴叨,我...
    開(kāi)封第一講書(shū)人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤凿宾,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后兼蕊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體初厚,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年孙技,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了产禾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡牵啦,死狀恐怖亚情,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情哈雏,我是刑警寧澤楞件,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站裳瘪,受9級(jí)特大地震影響土浸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜彭羹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一黄伊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧派殷,春花似錦还最、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)岂津。三九已至虱黄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吮成,已是汗流浹背橱乱。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留粱甫,地道東北人泳叠。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像茶宵,于是被迫代替她去往敵國(guó)和親危纫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

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