程序編譯(1)-目標(biāo)文件的編譯步驟

因?yàn)楣ぷ餍枰罱枰罱缙脚_(tái)工程。其中涉及到了依賴庫(kù)交叉編譯等工作撵枢。
因此趁這個(gè)機(jī)會(huì)寫一個(gè)關(guān)于c/c++編譯器的工作機(jī)制的小系列吠架,

前言

廣義上的"編譯"指的是由代碼芙贫、模塊、資源等構(gòu)建成機(jī)器碼的過(guò)程傍药。狹義上的"編譯"則指的是源代碼到匯編代碼的過(guò)程磺平。而標(biāo)題中的"編譯"則是廣義上的。那為什么需要了解其中的原理呢拐辽?

了解原理可以讓我們解決編譯過(guò)程中遇到的任何問(wèn)題都可以快速定位和解決

基本過(guò)程

c/c++廣義上的編譯都需要經(jīng)過(guò)以下這4步:預(yù)處理(Prepressing)->編譯(Compilation)->匯編(Assembly)->鏈接(Linking)

示例代碼如下:

#include <stdio.h>

#define DEF_VAR 100

static int kStaticInitVar = 10;
static int kStaticUnnitVar;

void func(int var)
{
    printf("%s-var:%d\n",__FUNCTION__, var);
}

int main()
{
    static int localStaticInitVar = 10;
    static int localStaticUnintVar;

    func(kStaticInitVar + localStaticInitVar + DEF_VAR);
    return 0;
}

整個(gè)編譯過(guò)程可以通過(guò)gcc -v test.c -o test.out查看拣挪,結(jié)果如下:

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/10/lto-wrapper
Target: arm-linux-gnueabihf
Configured with: ../src/configure -v --with-pkgversion='Raspbian 10.2.1-6+rpi1' --with-bugurl=file:///usr/share/doc/gcc-10/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-10 --program-prefix=arm-linux-gnueabihf- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libitm --disable-libquadmath --disable-libquadmath-support --enable-plugin --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-sjlj-exceptions --with-arch=armv6 --with-fpu=vfp --with-float=hard --disable-werror --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 10.2.1 20210110 (Raspbian 10.2.1-6+rpi1)
COLLECT_GCC_OPTIONS='-v' '-o' 'test.out'  '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp'
 /usr/lib/gcc/arm-linux-gnueabihf/10/cc1 -quiet -v -imultilib . -imultiarch arm-linux-gnueabihf test.c -quiet -dumpbase test.c -mfloat-abi=hard -mfpu=vfp -mtls-dialect=gnu -marm -march=armv6+fp -auxbase test -version -o /tmp/ccr8xe6E.s
GNU C17 (Raspbian 10.2.1-6+rpi1) version 10.2.1 20210110 (arm-linux-gnueabihf)
        compiled by GNU C version 10.2.1 20210110, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.0, isl version isl-0.23-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include/arm-linux-gnueabihf"
ignoring nonexistent directory "/usr/lib/gcc/arm-linux-gnueabihf/10/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/arm-linux-gnueabihf/10/../../../../arm-linux-gnueabihf/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/arm-linux-gnueabihf/10/include
 /usr/local/include
 /usr/include/arm-linux-gnueabihf
 /usr/include
End of search list.
GNU C17 (Raspbian 10.2.1-6+rpi1) version 10.2.1 20210110 (arm-linux-gnueabihf)
        compiled by GNU C version 10.2.1 20210110, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.0, isl version isl-0.23-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: b0c2f0ffcfbe7fc710aaf45c31c63944
COLLECT_GCC_OPTIONS='-v' '-o' 'test.out'  '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp'
 as -v -march=armv6 -mfloat-abi=hard -mfpu=vfp -meabi=5 -o /tmp/ccT9vuDF.o /tmp/ccr8xe6E.s
GNU assembler version 2.35.2 (arm-linux-gnueabihf) using BFD version (GNU Binutils for Raspbian) 2.35.2
COMPILER_PATH=/usr/lib/gcc/arm-linux-gnueabihf/10/:/usr/lib/gcc/arm-linux-gnueabihf/10/:/usr/lib/gcc/arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/10/:/usr/lib/gcc/arm-linux-gnueabihf/
LIBRARY_PATH=/usr/lib/gcc/arm-linux-gnueabihf/10/:/usr/lib/gcc/arm-linux-gnueabihf/10/../../../arm-linux-gnueabihf/:/usr/lib/gcc/arm-linux-gnueabihf/10/../../../:/lib/arm-linux-gnueabihf/:/lib/:/usr/lib/arm-linux-gnueabihf/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-o' 'test.out'  '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp'
 /usr/lib/gcc/arm-linux-gnueabihf/10/collect2 -plugin /usr/lib/gcc/arm-linux-gnueabihf/10/liblto_plugin.so -plugin-opt=/usr/lib/gcc/arm-linux-gnueabihf/10/lto-wrapper -plugin-opt=-fresolution=/tmp/ccvxcalC.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -dynamic-linker /lib/ld-linux-armhf.so.3 -X --hash-style=gnu --as-needed -m armelf_linux_eabi -o test.out /usr/lib/gcc/arm-linux-gnueabihf/10/../../../arm-linux-gnueabihf/crt1.o /usr/lib/gcc/arm-linux-gnueabihf/10/../../../arm-linux-gnueabihf/crti.o /usr/lib/gcc/arm-linux-gnueabihf/10/crtbegin.o -L/usr/lib/gcc/arm-linux-gnueabihf/10 -L/usr/lib/gcc/arm-linux-gnueabihf/10/../../../arm-linux-gnueabihf -L/usr/lib/gcc/arm-linux-gnueabihf/10/../../.. -L/lib/arm-linux-gnueabihf -L/usr/lib/arm-linux-gnueabihf /tmp/ccT9vuDF.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/arm-linux-gnueabihf/10/crtend.o /usr/lib/gcc/arm-linux-gnueabihf/10/../../../arm-linux-gnueabihf/crtn.o
COLLECT_GCC_OPTIONS='-v' '-o' 'test.out'  '-mfloat-abi=hard' '-mfpu=vfp' '-mtls-dialect=gnu' '-marm' '-march=armv6+fp'

我們可以看到,在整個(gè)編譯過(guò)程中使用到了cc1俱诸、as菠劝、collect2工具來(lái)完成預(yù)處理(Prepressing)->編譯(Compilation)->匯編(Assembly)->鏈接(Linking)整個(gè)過(guò)程的。由此可知gcc是通過(guò)間接調(diào)用各種程序來(lái)完成編譯(廣義)過(guò)程睁搭,其中cc1完成了預(yù)處理和編譯過(guò)程赶诊,as完成匯編過(guò)程,collect2完成鏈接過(guò)程介袜。

  • cc1:也是通過(guò)間接調(diào)用cpp(C Pre-Processor)c預(yù)處理器進(jìn)行預(yù)處理甫何,自身進(jìn)行編譯
  • as:匯編器,將匯編代碼轉(zhuǎn)化為機(jī)器碼
  • collect2:實(shí)際上的鏈接器是ld遇伞,gcc是通過(guò)調(diào)用collect2來(lái)間接調(diào)用ld進(jìn)而進(jìn)行鏈接的辙喂,感興趣可以閱讀[collect2](collect2 | 懶惰的程序員 (wanglianghome.org))這邊文章

<center class="half">
<img src="https://jesonblogbucket.oss-cn-shenzhen.aliyuncs.com/編譯基本流程.png" width="800"/>
</center>

預(yù)處理

gcc -E test.c -o test.i,參數(shù)-E表示只進(jìn)行預(yù)處理鸠珠,不進(jìn)行后續(xù)操作巍耗,生成test.i文件。效果等同于使用預(yù)處理器cpp

預(yù)處理后的結(jié)果如下渐排,由于文本過(guò)長(zhǎng)炬太,只粘貼關(guān)鍵部分

# 1 "test.c"
/*中間是頭文件stdio.h遞歸展開(kāi)后的結(jié)果*/
# 5 "test.c"
static int kStaticInitVar = 10;
static int kStaticUnnitVar;

void func(int var)
{
    printf("%s-var:%d\n",__FUNCTION__, var);
}

int main()
{
    static int localStaticInitVar = 10;
    static int localStaticUnintVar;

    func(kStaticInitVar + localStaticInitVar + 100); // DEF_VAR宏被替換
    return 0;
}

預(yù)編譯規(guī)則如下:

  • 替換所有宏定義
  • 處理所有條件預(yù)編譯指令,#if驯耻、#elif亲族、#endif等等
  • 遞歸展開(kāi)所有用到的#include頭文件包含指令
  • 刪除所有注釋
  • 添加行號(hào)以及文件標(biāo)識(shí)炒考,便于報(bào)錯(cuò)提示以及生成調(diào)試信息

編譯

gcc -S test.i -o test.s,參數(shù)-S表示只進(jìn)行預(yù)處理霎迫、編譯(狹義上)并生成匯編代碼斋枢,當(dāng)然可以用test.c生成匯編代碼,使用test.i是因?yàn)槠錇轭A(yù)編譯的產(chǎn)物知给,方便流程講解瓤帚。

編譯過(guò)程主要包括這幾個(gè)過(guò)程詞法分析、語(yǔ)法分析涩赢、語(yǔ)義分析戈次、優(yōu)化代碼。以下我只做總結(jié)概括筒扒,詳情見(jiàn):《程序員的自我修養(yǎng)-鏈接怯邪、裝載與庫(kù)》-2.2章節(jié):

詞法分析

由掃描器掃描源代碼,將關(guān)鍵字霎肯、標(biāo)識(shí)符擎颖、字面量榛斯、操作符進(jìn)行歸納和分類观游,并存儲(chǔ)到表中,供語(yǔ)法分析環(huán)節(jié)使用驮俗。

語(yǔ)法分析

把掃描器產(chǎn)生的記號(hào)生成以表達(dá)式為節(jié)點(diǎn)的語(yǔ)法樹(shù)懂缕,整個(gè)分析過(guò)程采用了上下文無(wú)關(guān)語(yǔ)法(Context-free Grammar)(感興趣可以深入了解,工作中基本用不上)王凑。通過(guò)了語(yǔ)法分析并不代表代碼過(guò)關(guān)了搪柑,此過(guò)程只是確認(rèn)最小表達(dá)式是否符合語(yǔ)法。

此圖引用至《程序員的自我修養(yǎng)-鏈接索烹、裝載與庫(kù)》工碾,侵刪~

<center class="half">
<img src="https://jesonblogbucket.oss-cn-shenzhen.aliyuncs.com/鏈接與庫(kù)-語(yǔ)法樹(shù).jpg" width="800"/>

程序員的自我修養(yǎng)-鏈接、裝載與庫(kù)-語(yǔ)法樹(shù)
</center>

語(yǔ)義分析

只進(jìn)行語(yǔ)法分析是遠(yuǎn)遠(yuǎn)不夠的百姓,好比每個(gè)詞語(yǔ)都沒(méi)問(wèn)題渊额,但是不按照語(yǔ)法進(jìn)行有意義的組合拿別人就無(wú)法理解。編譯器也一樣垒拢,例如兩個(gè)指針的乘法運(yùn)算是無(wú)意義的旬迹。

語(yǔ)義分析分為靜態(tài)語(yǔ)義動(dòng)態(tài)語(yǔ)義。靜態(tài)語(yǔ)義是指編譯期可以確定的求类,動(dòng)態(tài)語(yǔ)義指的是在運(yùn)行時(shí)候才能確定的語(yǔ)義奔垦。

代碼優(yōu)化

編譯器通過(guò)分析源代碼,識(shí)別出其中可以進(jìn)行優(yōu)化的部分, 并進(jìn)行調(diào)整以改善程序性能尸疆,常見(jiàn)的優(yōu)化例如常量傳播椿猎、常量折疊惶岭,在c++中的有返回值優(yōu)化(RVO)等,當(dāng)然編譯器所作的優(yōu)化是有限的~

匯編

gcc test.s -o test.o表示將匯編代碼轉(zhuǎn)化為機(jī)器碼犯眠,也等同于gcc -c test.c -o test.o

鏈接

鏈接過(guò)程本質(zhì)上就是將引用的外部符號(hào)進(jìn)行地址修正的過(guò)程~test.c中并沒(méi)有實(shí)現(xiàn)printf函數(shù)俗他。我們用nm命令來(lái)看看test.o的符號(hào)列表,nm -a test.o

00000000 n .ARM.attributes
00000000 b .bss
00000000 n .comment
00000000 d .data
00000000 T func
0000000c r __FUNCTION__.2
00000000 d kStaticInitVar
00000000 b kStaticUnnitVar
00000004 d localStaticInitVar.1
00000004 b localStaticUnintVar.0
00000034 T main
00000000 n .note.GNU-stack
         U printf
00000000 r .rodata
00000000 a test.c
00000000 t .text

其中printf符號(hào)的狀態(tài)是U阔逼,表示符號(hào)在當(dāng)前文件中是未定義的兆衅。然后執(zhí)行下面命令生成test.out

注意:下面命令只是用于與我擁有相同環(huán)境,下面命令只是我在collect2命令基礎(chǔ)上將參數(shù)/tmp/ccT9vuDF.o替換為test.o

/usr/lib/gcc/arm-linux-gnueabihf/10/collect2 -plugin /usr/lib/gcc/arm-linux-gnueabihf/10/liblto_plugin.so -plugin-opt=/usr/lib/gcc/arm-linux-gnueabihf/10/lto-wrapper -plugin-opt=-fresolution=/tmp/ccvxcalC.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -dynamic-linker /lib/ld-linux-armhf.so.3 -X --hash-style=gnu --as-needed -m armelf_linux_eabi -o test.out /usr/lib/gcc/arm-linux-gnueabihf/10/../../../arm-linux-gnueabihf/crt1.o /usr/lib/gcc/arm-linux-gnueabihf/10/../../../arm-linux-gnueabihf/crti.o /usr/lib/gcc/arm-linux-gnueabihf/10/crtbegin.o -L/usr/lib/gcc/arm-linux-gnueabihf/10 -L/usr/lib/gcc/arm-linux-gnueabihf/10/../../../arm-linux-gnueabihf -L/usr/lib/gcc/arm-linux-gnueabihf/10/../../.. -L/lib/arm-linux-gnueabihf -L/usr/lib/arm-linux-gnueabihf test.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/arm-linux-gnueabihf/10/crtend.o /usr/lib/gcc/arm-linux-gnueabihf/10/../../../arm-linux-gnueabihf/crtn.o

查看test.out符號(hào)嗜浮,nm -a test.out

00000000 a
         U abort@GLIBC_2.4
000104e8 r all_implied_fbits
0001058c r all_implied_fbits
00000000 n .ARM.attributes
0001061c r .ARM.exidx
00021030 b .bss
0002103c B __bss_end__
0002103c B _bss_end__
00021030 B __bss_start
00021030 B __bss_start__
00010354 t call_weak_fn
00000000 n .comment
00021030 b completed.0
00000000 a crtstuff.c
00000000 a crtstuff.c
00021020 d .data
00021020 D __data_start
00021020 W data_start
00010378 t deregister_tm_clones
000103dc t __do_global_dtors_aux
00020f14 d __do_global_dtors_aux_fini_array_entry
00021024 D __dso_handle
00020f18 d .dynamic
00020f18 d _DYNAMIC
00010230 r .dynstr
000101e0 r .dynsym
00021030 D _edata
00010624 r .eh_frame
00000000 a elf-init.oS
0002103c B __end__
0002103c B _end
000104dc t .fini
000104dc T _fini
00020f14 d .fini_array
00010404 t frame_dummy
00020f10 d __frame_dummy_init_array_entry
00010624 r __FRAME_END__
00010408 T func
00010584 r __FUNCTION__.2
00021000 d _GLOBAL_OFFSET_TABLE_
         w __gmon_start__
000101b4 r .gnu.hash
00010274 r .gnu.version
00010280 r .gnu.version_r
00021000 d .got
000102c8 t .init
000102c8 T _init
00020f10 d .init_array
00020f14 d __init_array_end
00020f10 d __init_array_start
00010154 r .interp
000104e4 R _IO_stdin_used
00021028 d kStaticInitVar
00021034 b kStaticUnnitVar
000104d8 T __libc_csu_fini
00010478 T __libc_csu_init
         U __libc_start_main@GLIBC_2.4
0002102c d localStaticInitVar.1
00021038 b localStaticUnintVar.0
0001043c T main
00010194 r .note.ABI-tag
00010170 r .note.gnu.build-id
000102d4 t .plt
         U printf@GLIBC_2.4
000103a4 t register_tm_clones
000102a0 r .rel.dyn
000102a8 r .rel.plt
000104e4 r .rodata
00010318 T _start
00000000 a test.c
00010318 t .text
00021030 D __TMC_END__
00000000 a /usr/lib/gcc/arm-linux-gnueabihf/10/../../../arm-linux-gnueabihf/crt1.o
00000000 a /usr/lib/gcc/arm-linux-gnueabihf/10/../../../arm-linux-gnueabihf/crti.o
00000000 a /usr/lib/gcc/arm-linux-gnueabihf/10/../../../arm-linux-gnueabihf/crtn.o

我們對(duì)比一下可以很容易發(fā)現(xiàn)一些變化:

  1. printf符號(hào)變成了printf@GLIBC_2.4且還是未定義:此符號(hào)gcc在鏈接時(shí)根據(jù)當(dāng)前版本修改符號(hào)羡亩,使得在運(yùn)行程序而動(dòng)態(tài)鏈接時(shí)不會(huì)鏈接到其他gcc版本的printf
  2. 很多符號(hào)的地址都被修正了,符號(hào)func符號(hào)地址從00000000被修正為00010408:?jiǎn)为?dú)模塊(*.o或者*.obj)的編譯時(shí)編譯器并不知道func的地址
  3. 符號(hào)增多:目標(biāo)文件和可執(zhí)行文件elf文件格式存在差異危融,例如增加了.dynamic段相關(guān)信息畏铆,即動(dòng)態(tài)鏈接信息
  4. 其他(有時(shí)間再研究研究)

當(dāng)前演示的鏈接過(guò)程并不是靜態(tài)鏈接。如果需要進(jìn)行靜態(tài)鏈接則需要加上-static參數(shù)吉殃。靜態(tài)鏈接比較簡(jiǎn)單辞居,說(shuō)白了就是遞歸的將所有引用到的符號(hào)歸檔到一個(gè)文件中,因此靜態(tài)鏈接后的文件都會(huì)大上許多~經(jīng)常與靜態(tài)鏈接一起提及的就是動(dòng)態(tài)鏈接蛋勺。動(dòng)態(tài)鏈接的鏈接時(shí)期是程序運(yùn)行時(shí)瓦灶,當(dāng)前鏈接環(huán)節(jié)可以理解為為動(dòng)態(tài)鏈接做準(zhǔn)備。

靜態(tài)鏈接和動(dòng)態(tài)鏈接最主要的區(qū)別:兩者的鏈接時(shí)期不一致抱完,靜態(tài)鏈接在程序編譯鏈接時(shí)期贼陶,動(dòng)態(tài)鏈接則是程序運(yùn)行時(shí)

這里可以說(shuō)內(nèi)容比較多,現(xiàn)在只是簡(jiǎn)單提一嘴巧娱,后續(xù)會(huì)有專門的文章來(lái)聊聊這兩者具體的差異以及各自的機(jī)制~

最后總結(jié)一下鏈接過(guò)程:

  • 鏈接器就是在鏈接的時(shí)候自動(dòng)在所提供的依賴庫(kù)或者目標(biāo)文件(*.o或者*.obj)中搜索被引用的外部符號(hào)

  • 找到之后會(huì)將絕對(duì)地址指令重新修正碉怔,使其指向正確的地址。

  • 修正的過(guò)程被稱之為重定位禁添,被修正的地址入口稱之為重定位入口

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末撮胧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子老翘,更是在濱河造成了極大的恐慌芹啥,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,888評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酪捡,死亡現(xiàn)場(chǎng)離奇詭異叁征,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)逛薇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門捺疼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人永罚,你說(shuō)我怎么就攤上這事啤呼∥悦兀” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,386評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵官扣,是天一觀的道長(zhǎng)翅敌。 經(jīng)常有香客問(wèn)我,道長(zhǎng)惕蹄,這世上最難降的妖魔是什么蚯涮? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,726評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮卖陵,結(jié)果婚禮上遭顶,老公的妹妹穿的比我還像新娘。我一直安慰自己泪蔫,他們只是感情好棒旗,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著撩荣,像睡著了一般铣揉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上餐曹,一...
    開(kāi)封第一講書(shū)人閱讀 52,337評(píng)論 1 310
  • 那天逛拱,我揣著相機(jī)與錄音,去河邊找鬼凸主。 笑死橘券,一個(gè)胖子當(dāng)著我的面吹牛额湘,可吹牛的內(nèi)容都是我干的卿吐。 我是一名探鬼主播,決...
    沈念sama閱讀 40,902評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼锋华,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼嗡官!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起毯焕,我...
    開(kāi)封第一講書(shū)人閱讀 39,807評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤衍腥,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后纳猫,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體婆咸,經(jīng)...
    沈念sama閱讀 46,349評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評(píng)論 3 340
  • 正文 我和宋清朗相戀三年芜辕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了尚骄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,567評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡侵续,死狀恐怖倔丈,靈堂內(nèi)的尸體忽然破棺而出憨闰,到底是詐尸還是另有隱情,我是刑警寧澤需五,帶...
    沈念sama閱讀 36,242評(píng)論 5 350
  • 正文 年R本政府宣布鹉动,位于F島的核電站,受9級(jí)特大地震影響宏邮,放射性物質(zhì)發(fā)生泄漏泽示。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評(píng)論 3 334
  • 文/蒙蒙 一蜜氨、第九天 我趴在偏房一處隱蔽的房頂上張望边琉。 院中可真熱鬧,春花似錦记劝、人聲如沸变姨。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,420評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)定欧。三九已至,卻和暖如春怒竿,著一層夾襖步出監(jiān)牢的瞬間砍鸠,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,531評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工耕驰, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留爷辱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,995評(píng)論 3 377
  • 正文 我出身青樓朦肘,卻偏偏與公主長(zhǎng)得像饭弓,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子媒抠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評(píng)論 2 359

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