Rust的二進(jìn)制文件

前言

此文為舊文新發(fā)遣臼,這是我之前翻譯文章翘单,因?yàn)楹?jiǎn)書有段時(shí)間做內(nèi)部審查彩届,不能發(fā)表文章伪冰,所以當(dāng)時(shí)寫完放在了其它平臺(tái)上,今天將這篇移到簡(jiǎn)書上來(lái)樟蠕。因?yàn)闆](méi)有用無(wú)GC的語(yǔ)言寫過(guò)上生產(chǎn)的代碼贮聂,一直有一些遺憾,近年來(lái)Rust崛起了寨辩,從TiKVLibra等項(xiàng)目大膽采用Rust吓懈,這門語(yǔ)言逐漸為人所接受也成熟起來(lái),遂借著翻譯的機(jī)會(huì)靡狞,學(xué)習(xí)這門語(yǔ)言新貴耻警,順便補(bǔ)一下操作系統(tǒng)欠下的技術(shù)債


A Freestanding Rust Binary

獨(dú)立的Rust二進(jìn)制文件

若要編寫我們自己的操作系統(tǒng)內(nèi)核, 第一步便是創(chuàng)建一個(gè)不鏈接標(biāo)準(zhǔn)庫(kù)(注解:類比為C語(yǔ)言中的stdlib)的Rust可執(zhí)行文件。這一步是為了在沒(méi)有底層操作系統(tǒng)支持的情況下, 使得Rust能夠在裸機(jī)上運(yùn)行甘穿。

這個(gè)博客是在GitHub上公開發(fā)布的腮恩。如果您有任何問(wèn)題或疑問(wèn),歡迎提issue温兼。您也可以在底部留下評(píng)論秸滴。本文的完整源代碼可以在post-01分支中找到。

介紹

要編寫操作系統(tǒng)內(nèi)核募判,我們需要不依賴于任何操作系統(tǒng)特性的代碼荡含。這意味著我們不能使用線程、文件兰伤、堆內(nèi)存内颗、網(wǎng)絡(luò)钧排、隨機(jī)數(shù)敦腔、標(biāo)準(zhǔn)輸出或任何其他需要OS抽象或特定硬件的特性。必須如此恨溜,因?yàn)槲覀冋趪L試編寫自己的操作系統(tǒng)和驅(qū)動(dòng)程序符衔。

這意味著我們不能使用大多數(shù)Rust標(biāo)準(zhǔn)庫(kù),但是我們可以使用很多其它Rust特性糟袁。比如我們可以使用迭代器判族、閉包模式匹配项戴、選項(xiàng)結(jié)果形帮、字符串格式化,當(dāng)然還有所有權(quán)系統(tǒng)周叮。這些特性讓我們能用一種非常有表現(xiàn)力的辩撑、高層次的方式編寫內(nèi)核,不必?fù)?dān)心未定義的行為或內(nèi)存安全問(wèn)題仿耽。

為了在Rust中創(chuàng)建操作系統(tǒng)內(nèi)核合冀,我們需要?jiǎng)?chuàng)建一個(gè)可執(zhí)行文件,它可以在沒(méi)有底層操作系統(tǒng)運(yùn)行的情況下運(yùn)行项贺。這種可執(zhí)行文件通常被稱為"獨(dú)立的"或"裸金屬"可執(zhí)行文件君躺。

禁用標(biāo)準(zhǔn)庫(kù)

默認(rèn)情況下,所有Rust的項(xiàng)目都需要鏈接標(biāo)準(zhǔn)庫(kù)开缎,而標(biāo)準(zhǔn)庫(kù)的特性又取決于操作系統(tǒng)棕叫,比如線程、文件或網(wǎng)絡(luò)奕删。它還依賴于與操作系統(tǒng)緊密交互的C標(biāo)準(zhǔn)庫(kù)libc谍珊。因?yàn)槲覀兊挠?jì)劃正是編寫一個(gè)操作系統(tǒng),所以我們不能使用任何依賴于操作系統(tǒng)的庫(kù)。因此砌滞,我們可以通過(guò)no_std屬性來(lái)禁用標(biāo)準(zhǔn)庫(kù)侮邀。

我們首先要通過(guò)創(chuàng)建一個(gè)由cargo管理依賴的(注解:Cargo是Rust程序的包管理器)Rust應(yīng)用程序。最簡(jiǎn)單的方法是通過(guò)命令行:

cargo new blog_os --bin --edition 2018

我將項(xiàng)目命名為blog_os贝润,當(dāng)然您可以選擇自己的名稱绊茧。-—bin指定我們想要?jiǎng)?chuàng)建一個(gè)可執(zhí)行的二進(jìn)制文件(與lib庫(kù)有所不同),--edition 2018指定我們的項(xiàng)目使用Rust的2018版本打掘。當(dāng)我們運(yùn)行該命令時(shí)华畏,cargo為我們創(chuàng)建了以下目錄結(jié)構(gòu):

blog_os
├── Cargo.toml
└── src
    └── main.rs

Cargo.toml包含有項(xiàng)目的配置, 比如項(xiàng)目名尊蚁、作者亡笑、版本號(hào)及其依賴, src/main.rs則包括項(xiàng)目根目錄及main函數(shù)横朋。您可以通過(guò)cargo build編譯您的項(xiàng)目仑乌,然后在子目錄target/debug中運(yùn)行編譯后的blog_os二進(jìn)制文件。

no_std屬性

現(xiàn)在琴锭,我們的項(xiàng)目隱式地鏈接了標(biāo)準(zhǔn)庫(kù)晰甚。讓我們通過(guò)添加no_std屬性來(lái)禁用它:

// main.rs

#![no_std]

fn main() {
    println!("Hello, world!");
}

通過(guò)運(yùn)行cargo build編譯項(xiàng)目時(shí),會(huì)發(fā)生以下錯(cuò)誤:

error: cannot find macro `println!` in this scope
 --> src/main.rs:4:5
  |
4 |     println!("Hello, world!");
  |

這個(gè)錯(cuò)誤的原因是println宏是標(biāo)準(zhǔn)庫(kù)的一部分决帖,它會(huì)打印標(biāo)準(zhǔn)輸出厕九,這是操作系統(tǒng)提供的一個(gè)特殊的文件描述符。我們禁用后就不能再打印東西了地回。

所以扁远,讓我們刪除打印,將main函數(shù)置空并再次嘗試:

// main.rs

#![no_std]

fn main() {}
> cargo build
error: `#[panic_handler]` function required, but not found
error: language item required, but not found: `eh_personality`

如上所示刻像,現(xiàn)在編譯器缺少一個(gè)#[panic_handler]函數(shù)和一個(gè)語(yǔ)言項(xiàng)畅买。

Panic的實(shí)現(xiàn)

panic_handler是編譯器在發(fā)生panic(注解:可理解為異常)時(shí)應(yīng)該調(diào)用的函數(shù)。標(biāo)準(zhǔn)庫(kù)提供了自己的panic handler函數(shù)绎速,但是在no_std環(huán)境中皮获,我們需要自己定義它:

// in main.rs

use core::panic::PanicInfo;

/// This function is called on panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

PanicInfo參數(shù)包含發(fā)生異常的文件及其對(duì)應(yīng)的行,以及可選的異常消息纹冤。該函數(shù)應(yīng)該永遠(yuǎn)不會(huì)返回洒宝,因此需要通過(guò)返回!類型將其標(biāo)記為一個(gè)發(fā)散函數(shù)。在這個(gè)函數(shù)中我們能做的不多萌京,所以我們就讓它無(wú)限循環(huán)吧雁歌。

eh_personality語(yǔ)言項(xiàng)

語(yǔ)言項(xiàng)是編譯器內(nèi)部需要的特殊函數(shù)和類型。例如知残,Copy是一個(gè)語(yǔ)言項(xiàng)靠瞎,它告訴編譯器哪些類型具有[copy](https://doc.rust-lang.org/nightly/core/marker/trait.Copy.html)語(yǔ)義。當(dāng)我們查看實(shí)現(xiàn)時(shí),我們看到它具有特殊的#[lang = "copy"]屬性乏盐,該屬性將其定義為了一個(gè)語(yǔ)言項(xiàng)佳窑。

提供自己的語(yǔ)言項(xiàng)的實(shí)現(xiàn)是可能的,但這只能作為最后的手段父能。原因是語(yǔ)言項(xiàng)是高度不穩(wěn)定的實(shí)現(xiàn)細(xì)節(jié)神凑,甚至沒(méi)有類型檢查(因此編譯器甚至沒(méi)有檢查函數(shù)是否具有正確的參數(shù)類型)。幸運(yùn)的是何吝,有一種更穩(wěn)定的方法可以修復(fù)上述語(yǔ)言項(xiàng)錯(cuò)誤溉委。

eh_personality語(yǔ)言項(xiàng)標(biāo)記了一個(gè)用于實(shí)現(xiàn)stackunwinding(注解:?)的函數(shù)爱榕。默認(rèn)情況下瓣喊,Rust使用unwind來(lái)運(yùn)行所有活動(dòng)堆棧變量的析構(gòu)函數(shù),以防出現(xiàn)異常黔酥。這確保釋放所有使用的內(nèi)存藻三,并允許父線程捕捉異常并繼續(xù)執(zhí)行。然而絮爷,unwind是一個(gè)復(fù)雜的過(guò)程趴酣,需要一些特定于操作系統(tǒng)的庫(kù)(例如Linux上的libunwind或Windows上的結(jié)構(gòu)化異常處理)梨树,所以我們不想在操作系統(tǒng)上使用它坑夯。

禁用Unwinding

還有其他一些用例不希望運(yùn)行unwinding,所以Rust提供了一個(gè)在異常時(shí)中止的選項(xiàng)抡四。這禁止生成展開符號(hào)信息柜蜈,從而大大減小了二進(jìn)制文件的大小。我們可以在多個(gè)地方禁用unwind指巡。最簡(jiǎn)單的方法是在我們的Cargo.toml加上以下幾行淑履。

[profile.dev]
panic = "abort"

[profile.release]
panic = "abort"

這將為dev概要文件(用于構(gòu)建開發(fā)版本)和release概要文件(用于構(gòu)建release版本)設(shè)置終止panic策略(注解:直接中斷,不展示異常堆棧信息)≡逖現(xiàn)在不再需要eh_personality語(yǔ)言項(xiàng)秘噪。

現(xiàn)在我們修正了上面的兩個(gè)錯(cuò)誤。然而勉耀,如果我們現(xiàn)在編譯它指煎,會(huì)發(fā)現(xiàn)另外一個(gè)錯(cuò)誤:

> cargo build
error: requires `start` lang_item

我們的程序缺少定義入口點(diǎn)的start語(yǔ)言項(xiàng)。

start屬性

有人可能認(rèn)為main(注解:一直以來(lái)就是這樣認(rèn)為的)函數(shù)是運(yùn)行程序時(shí)調(diào)用的第一個(gè)函數(shù)便斥。然而至壤,大多數(shù)語(yǔ)言都有一個(gè)運(yùn)行時(shí)系統(tǒng),它負(fù)責(zé)垃圾收集(例如Java)或軟件線程(例如Go中的goroutines)枢纠。這個(gè)運(yùn)行時(shí)需要在main之前調(diào)用像街,因?yàn)樗枰跏蓟约骸?/p>

在鏈接標(biāo)準(zhǔn)庫(kù)的典型Rust二進(jìn)制文件中,執(zhí)行從一個(gè)名為crt0("C runtime zero")的C運(yùn)行時(shí)庫(kù)開始,該庫(kù)為C應(yīng)用程序設(shè)置了環(huán)境镰绎。這包括創(chuàng)建堆棧并將參數(shù)放在正確的寄存器中脓斩。然后C運(yùn)行時(shí)調(diào)用Rust運(yùn)行時(shí)的入口點(diǎn),該入口點(diǎn)由start language項(xiàng)標(biāo)記畴栖。Rust只有一個(gè)非常小的運(yùn)行時(shí)俭厚,它負(fù)責(zé)一些小事,比如設(shè)置堆棧溢出保護(hù)或在panic上打印回溯驶臊。運(yùn)行時(shí)最后調(diào)用main函數(shù)挪挤。

我們獨(dú)立的可執(zhí)行文件不能訪問(wèn)Rust運(yùn)行時(shí)和crt0,所以我們需要定義自己的入口點(diǎn)关翎。實(shí)現(xiàn)start語(yǔ)言項(xiàng)沒(méi)有幫助扛门,因?yàn)樗匀恍枰猚rt0。相反纵寝,我們需要直接覆蓋crt0入口點(diǎn)论寨。

覆蓋入口函數(shù)

為了告訴Rust編譯器我們不想使用普通的入口鏈接函數(shù),我們添加了#![no_main]屬性爽茴。

#![no_std]
#![no_main]

use core::panic::PanicInfo;

/// This function is called on panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

您可能會(huì)注意到我們刪除了主要功能葬凳。 原因是如果沒(méi)有調(diào)用它的底層運(yùn)行時(shí),main就沒(méi)有意義室奏。 我們現(xiàn)在用我們自己的_start函數(shù)覆蓋操作系統(tǒng)入口函數(shù):

#[no_mangle]
pub extern "C" fn _start() -> ! {
    loop {}
}

通過(guò)使用#[no_mangle]屬性火焰,我們禁用名稱修改以確保Rust編譯器確實(shí)輸出名為_start的函數(shù)。如果沒(méi)有該屬性胧沫,編譯器將生成一些神秘的_ZN3blog_os4_start7hb173fedf945531caE符號(hào)昌简,以便為每個(gè)函數(shù)提供唯一的名稱。該屬性是必需的绒怨,因?yàn)槲覀冃枰谙乱徊街懈嬷溄悠鞯娜肟邳c(diǎn)函數(shù)的名稱纯赎。

我們還必須將函數(shù)標(biāo)記為extern"C",告訴編譯器它應(yīng)該使用此函數(shù)的C調(diào)用約定(而不是未指定的Rust調(diào)用約定)南蹂。命名函數(shù)_start的原因是這是大多數(shù)系統(tǒng)的默認(rèn)入口點(diǎn)名稱犬金。

符號(hào)返回類型意味著函數(shù)發(fā)散六剥,即不允許返回晚顷。這是必需的,因?yàn)槿魏魏瘮?shù)都不會(huì)調(diào)用入口點(diǎn)仗考,而是由操作系統(tǒng)或引導(dǎo)加載程序直接調(diào)用音同。因此,入口點(diǎn)不應(yīng)該返回秃嗜,而應(yīng)該是調(diào)用操作系統(tǒng)的退出系統(tǒng)調(diào)用权均。在我們的例子中顿膨,關(guān)閉機(jī)器可能是一個(gè)合理的操作,因?yàn)槿绻粋€(gè)獨(dú)立的二進(jìn)制返回叽赊,沒(méi)有什么可做的×滴郑現(xiàn)在,我們通過(guò)無(wú)休止地循環(huán)來(lái)滿足要求必指。

當(dāng)我們現(xiàn)在cargo build囊咏,我們得到一個(gè)丑陋的鏈接器錯(cuò)誤。

鏈接錯(cuò)誤

鏈接器是一個(gè)將生成的代碼組合成可執(zhí)行文件的程序塔橡。 由于Linux梅割,Windows和macOS系統(tǒng)的可執(zhí)行文件格式彼此不同,因此每個(gè)系統(tǒng)都有自己的鏈接器葛家,當(dāng)然可能會(huì)引發(fā)不同的錯(cuò)誤户辞。 錯(cuò)誤的根本原因是相同的:鏈接器的默認(rèn)配置假定我們的程序依賴于C運(yùn)行時(shí)。

要解決這些錯(cuò)誤癞谒,我們需要告訴鏈接器它不應(yīng)該包含C運(yùn)行時(shí)底燎。 我們可以通過(guò)將一組參數(shù)傳遞給鏈接器或構(gòu)建裸機(jī)目標(biāo)來(lái)實(shí)現(xiàn)。

為裸機(jī)編譯目標(biāo)文件

默認(rèn)情況下弹砚,Rust會(huì)嘗試構(gòu)建一個(gè)能夠在當(dāng)前系統(tǒng)環(huán)境中運(yùn)行的可執(zhí)行文件双仍。 例如,如果您在x86_64上使用Windows桌吃,Rust會(huì)嘗試構(gòu)建使用x86_64指令的.exe Windows可執(zhí)行文件朱沃。 此環(huán)境稱為“主機(jī)”系統(tǒng)。

為了描述不同的環(huán)境读存,Rust使用一個(gè)名為target triple的字符串为流。 您可以通過(guò)運(yùn)行rustc --version --verbose來(lái)查看主機(jī)系統(tǒng)的目標(biāo)三元組:

rustc 1.35.0-nightly (474e7a648 2019-04-07)
binary: rustc
commit-hash: 474e7a6486758ea6fc761893b1a49cd9076fb0ab
commit-date: 2019-04-07
host: x86_64-unknown-linux-gnu
release: 1.35.0-nightly
LLVM version: 8.0

以上輸出來(lái)自x86_64 Linux系統(tǒng)呕屎。 我們看到主機(jī)三元組是x86_64-unknown-linux-gnu让簿,它包括CPU架構(gòu)(x86_64),供應(yīng)商(未知)秀睛,操作系統(tǒng)(linux)和ABI(gnu)尔当。

通過(guò)編譯我們的主機(jī)三元組,Rust編譯器和鏈接器假定有一個(gè)底層操作系統(tǒng)蹂安,如Linux或Windows椭迎,默認(rèn)情況下使用C運(yùn)行時(shí),這會(huì)導(dǎo)致鏈接器錯(cuò)誤田盈。 因此畜号,為了避免鏈接器錯(cuò)誤,我們可以針對(duì)沒(méi)有底層操作系統(tǒng)的不同環(huán)境進(jìn)行編譯允瞧。

這種裸機(jī)環(huán)境的一個(gè)例子是thumbv7em-none-eabihf target triple简软,它描述了嵌入式ARM系統(tǒng)蛮拔。 細(xì)節(jié)并不重要,重要的是目標(biāo)三元組沒(méi)有底層操作系統(tǒng)痹升,由目標(biāo)三元組中的none表示建炫。 為了能夠?yàn)檫@個(gè)目標(biāo)進(jìn)行編譯,我們需要在rustup中添加它:

rustup target add thumbv7em-none-eabihf

這將下載系統(tǒng)的標(biāo)準(zhǔn)(和核心)庫(kù)的副本疼蛾。 現(xiàn)在我們可以為這個(gè)目標(biāo)構(gòu)建我們的獨(dú)立可執(zhí)行文件:

cargo build --target thumbv7em-none-eabihf

通過(guò)傳遞--target參數(shù)肛跌,交叉編譯我們的可執(zhí)行文件用于裸機(jī)目標(biāo)系統(tǒng)。 由于目標(biāo)系統(tǒng)沒(méi)有操作系統(tǒng)察郁,鏈接器不會(huì)嘗試鏈接C運(yùn)行時(shí)衍慎,并且我們的構(gòu)建成功而沒(méi)有任何鏈接器錯(cuò)誤。

這是我們用于構(gòu)建操作系統(tǒng)內(nèi)核的方法皮钠。 我們將使用描述x86_64裸機(jī)環(huán)境的自定義目標(biāo)西饵,而不是thumbv7em-none-eabihf。 細(xì)節(jié)將在下一篇文章中解釋鳞芙。

鏈接參數(shù)

除了為裸機(jī)系統(tǒng)進(jìn)行編譯之外眷柔,還可以通過(guò)將一組參數(shù)傳遞給鏈接器來(lái)解決鏈接器錯(cuò)誤。 這不是我們將用于內(nèi)核的方法原朝,因此本節(jié)是可選的驯嘱,僅提供完整性。 單擊下面的“鏈接器參數(shù)”以顯示可選內(nèi)容喳坠。

總結(jié)

最小的獨(dú)立Rust二進(jìn)制文件如下所示:

src/main.rs:

#![no_std] // don't link the Rust standard library
#![no_main] // disable all Rust-level entry points

use core::panic::PanicInfo;

#[no_mangle] // don't mangle the name of this function
pub extern "C" fn _start() -> ! {
    // this function is the entry point, since the linker looks for a function
    // named `_start` by default
    loop {}
}

/// This function is called on panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

Cargo.toml:

[package]
name = "crate_name"
version = "0.1.0"
authors = ["Author Name <author@example.com>"]

# the profile used for `cargo build`
[profile.dev]
panic = "abort" # disable stack unwinding on panic

# the profile used for `cargo build --release`
[profile.release]
panic = "abort" # disable stack unwinding on panic

要構(gòu)建這個(gè)二進(jìn)制文件鞠评,我們需要根據(jù)相應(yīng)的裸機(jī)來(lái)編譯,例如thumbv7em-none-eabihf

cargo build --target thumbv7em-none-eabihf

或者壕鹉,我們可以通過(guò)傳遞其他鏈接參數(shù)編譯成不同的操作系統(tǒng)所所需的可執(zhí)行文件:

# Linux
cargo rustc -- -C link-arg=-nostartfiles
# Windows
cargo rustc -- -C link-args="/ENTRY:_start /SUBSYSTEM:console"
# macOS
cargo rustc -- -C link-args="-e __start -static -nostartfiles"

請(qǐng)注意剃幌,這只是一個(gè)獨(dú)立的Rust二進(jìn)制文件的最小示例。 這個(gè)二進(jìn)制文件需要各種各樣的東西晾浴,例如在調(diào)用_start函數(shù)時(shí)初始化堆棧负乡。 因此,對(duì)于任何實(shí)際使用這種二進(jìn)制文件脊凰,可能需要更多步驟抖棘。

下一步

下一篇文章我們將會(huì)逐步討論二進(jìn)制文件轉(zhuǎn)換為最小操作系統(tǒng)內(nèi)核所需的步驟。 這包括創(chuàng)建自定義編譯目標(biāo)狸涌,將可執(zhí)行文件與引導(dǎo)加載程序相結(jié)合切省,以及學(xué)習(xí)如何在屏幕上打印內(nèi)容。

支持我

如果您喜歡這篇文章并想支持我帕胆,可以通過(guò)Donorbox朝捆,PatreonLiberapay聯(lián)系我。 謝謝懒豹!

原文:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末芙盘,一起剝皮案震驚了整個(gè)濱河市诊杆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌何陆,老刑警劉巖晨汹,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異贷盲,居然都是意外死亡淘这,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門巩剖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)铝穷,“玉大人,你說(shuō)我怎么就攤上這事佳魔∈锬簦” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵鞠鲜,是天一觀的道長(zhǎng)宁脊。 經(jīng)常有香客問(wèn)我,道長(zhǎng)贤姆,這世上最難降的妖魔是什么榆苞? 我笑而不...
    開封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮霞捡,結(jié)果婚禮上坐漏,老公的妹妹穿的比我還像新娘。我一直安慰自己碧信,他們只是感情好赊琳,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著砰碴,像睡著了一般躏筏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上衣式,一...
    開封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天寸士,我揣著相機(jī)與錄音,去河邊找鬼碴卧。 笑死,一個(gè)胖子當(dāng)著我的面吹牛乃正,可吹牛的內(nèi)容都是我干的住册。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼瓮具,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼荧飞!你這毒婦竟也來(lái)了凡人?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤叹阔,失蹤者是張志新(化名)和其女友劉穎挠轴,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體耳幢,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡岸晦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了睛藻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片启上。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖店印,靈堂內(nèi)的尸體忽然破棺而出冈在,到底是詐尸還是另有隱情,我是刑警寧澤按摘,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布包券,位于F島的核電站,受9級(jí)特大地震影響炫贤,放射性物質(zhì)發(fā)生泄漏兴使。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一照激、第九天 我趴在偏房一處隱蔽的房頂上張望发魄。 院中可真熱鬧,春花似錦俩垃、人聲如沸励幼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)苹粟。三九已至,卻和暖如春跃闹,著一層夾襖步出監(jiān)牢的瞬間嵌削,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工望艺, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留苛秕,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓找默,卻偏偏與公主長(zhǎng)得像艇劫,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子惩激,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348