Linux驅(qū)動之內(nèi)核模塊

一吁断、Linux內(nèi)核模塊簡介

1.1 Linux內(nèi)核模塊介紹

Linux內(nèi)核的整體結(jié)構(gòu)已經(jīng)非常龐大孵户,而其包含的組件也非常多宵距。我們怎樣把需要的部分都包含在內(nèi)核中呢?

一種方法是把所有需要的功能都編譯到Linux內(nèi)核略荡。這會導致兩個問題庵佣,一是生成的內(nèi)核會很大,二是如果我們要在現(xiàn)有的內(nèi)核中新增或刪除功能汛兜,將不得不重新編譯內(nèi)核巴粪。

有沒有一種機制使得編譯出的內(nèi)核本身并不需要包含所有功能,而在這些功能需要被使用的時候序无,其對應(yīng)的代碼被動態(tài)地加載到內(nèi)核中呢验毡?

Linux提供了這樣一種機制衡创,這種機制被稱為模塊(Module)帝嗡。模塊具有這樣的特點:

  • ++模塊本身不被編譯如內(nèi)核映像,從而控制了內(nèi)核的大小++璃氢;
  • ++模塊一旦被加載哟玷,它就和內(nèi)核中的其他部分完全一樣++;

模塊化的最大的好處是可以動態(tài)擴展應(yīng)用程序的功能而無需重新編譯鏈接生成一個新的應(yīng)用程序映像(或內(nèi)核)。這對應(yīng)Windows系統(tǒng)上為動態(tài)鏈接庫DDL(Dynamic Link Library)巢寡,對應(yīng)到Linux系統(tǒng)中為驅(qū)動模塊和應(yīng)用程序的共享庫so(shared object)喉脖。

模塊的機制使驅(qū)動程序與Linux內(nèi)核結(jié)合有兩種方式:在編譯內(nèi)核時,靜態(tài)地鏈接進內(nèi)核抑月;++在系統(tǒng)運行時树叽,以模塊加載的方式加載進內(nèi)核++。

1.2 Linux內(nèi)核模塊的構(gòu)成

一個Linux內(nèi)核模塊主要由如下幾個部分組成:

(1)模塊加載函數(shù)(一般需要)

當通過insmod或modprobe命令加載內(nèi)核模塊時谦絮,模塊的加載函數(shù)會被內(nèi)核執(zhí)行题诵,完成本模塊的相關(guān)初始化工作。

(2)模塊卸載函數(shù)(一般需要)

當通過rmmod命令卸載某模塊時层皱,模塊的卸載函數(shù)會自動被內(nèi)核執(zhí)行性锭,完成與加載函數(shù)相反的功能。

(3)模塊許可證聲明(必須)

許可證(LICENSE)聲明描述內(nèi)核模塊的許可權(quán)限叫胖,如果不聲明LICENSE草冈,模塊被加載時,將收到內(nèi)核被污染(kernel tainted)的警告瓮增。

在Linux 2.6內(nèi)核中怎棱,可接受的LICENSE包括“GPL”、“GPL v2”绷跑、“GPL and additional rights”蹄殃、“Dual BSD/GPL”、“Dual MPL/GPL”和“Proprietary”你踩。大多數(shù)情況下诅岩,內(nèi)核模塊應(yīng)遵循GPL兼容許可權(quán),Linux 2.6內(nèi)核模塊最常見的是以MODULE_LICENSE(“Dual BSD/GPL”);語句聲明模塊采用BSD/GPL雙LICENSE带膜。

(4)模塊參數(shù)(可選)

模塊參數(shù)是模塊被加載的時候可以被傳遞給它的值吩谦,它本身對應(yīng)模塊內(nèi)部的全局變量。

(5)模塊導出符號(可選)

內(nèi)核模塊可以導出符號(symbol膝藕,對應(yīng)于函數(shù)或變量)式廷,這樣其他模塊就可以使用本模塊中的變量或函數(shù)。

(6)模塊作者等信息聲明(可選)

1.3 一個簡單的Linux內(nèi)核模塊

一個基本的內(nèi)核模塊只需包含頭文件芭挽、模塊加載函數(shù)滑废、模塊卸載函數(shù)以及許可協(xié)議和一些描述信息。如代碼清單1.1所示袜爪。

代碼清單1.1 一個最簡單的Linux內(nèi)核模塊

#include <linux/init.h>    /* 頭文件 */
#include <linux/module.h>
   
static int hello_init(void)
{
   printk(KERN_INFO”Hello world enter.\n”);
   return 0;
}
   
static void hello_exit(void)
{
   printk(KERN_INFO”Hello world exit.\n”);
}
   
module_init(hello_init);
module_exit(hello_exit);
   
   /* 模塊說明信息 */
MODULE_LICENSE(“Dual BSD/GPL”);
MODULE_AUTHOR(“Aaron konishi:zh5202@163.com”);
MODULE_ALIAS(“A simplest module”);
MODULE_DESCRIPTION(“A simple Hello world module”);

編譯它會產(chǎn)生一個hello.ko目標文件蠕趁,通過“insmod ./hello.ko”命令可以加載它,通過“rmmod hello”命令可以卸載它辛馆,加載時輸出“Hello world enter.”俺陋,卸載時輸出“Hello world exit”。

注釋:內(nèi)核模塊中的輸出函數(shù)是內(nèi)核空間的printk()而非用戶空間的printf(),printk()用法與printf()基本相似腊状,但前者可以定義輸出級別诱咏。printk()可作為一種最基本的內(nèi)核調(diào)試手段,在Linux驅(qū)動的調(diào)試章節(jié)中將詳細講解這個函數(shù)缴挖。

內(nèi)核中已加載模塊的信息存在于/sys/module目錄下袋狞,加載hello.ko后,內(nèi)核中將包含/sys/module/hello目錄映屋,該目錄下又包含一個refcnt文件和一個sections目錄硕并,在/sys/module/hello目錄下運行“tree -a”得到如下目錄樹:

# tree -a
.
| -- holders
| -- initstate
| -- notes
|   `-- .note.gnu.build-id
| -- refcnt
| -- sections
|   | -- .bss
|   | -- .data
|   | -- .gnu.linkonce.this_module
|   | -- .note.gnu.build-id
|   | -- .rodata.str1.1
|   | -- .strtab
|   | -- .symtab
|   | -- .text
` -- srcversion
   
3 directories, 12 files

1.4 Linux模塊操作常用命令

在編寫、調(diào)試和使用Linux內(nèi)核模塊的過程中秧荆,常常會使用到lsmod倔毙、modprobe、rmmod和modinfo命令乙濒。

++lsmod命令可以獲得系統(tǒng)中加載了的所有模塊以及模塊間的依賴關(guān)系++陕赃,例如:

Module          Size   Used   by
hello            9      472    0
nls_iso8859_1    12     032    1
nls_cp437        13     696    1
vfat             18     816    1
fat              57     376    1  vfat
…

lsmod命令實際上是讀取并分析“/proc/modules”文件,與上述lsmod命令結(jié)果對應(yīng)的“/proc/modules”文件如下:

# cat /proc/modules
hello 9472 0 - Live 0xf953b000
nls_iso8859_1 12032 1 - Live 0xf950c000
nls_cp437 13696 1 - Live 0xf9561000
vfat 18816 1 - Live 0xf94f3000
…

++modprobe命令比insmod命令要強大颁股,它在加載某模塊時么库,會同時加載該模塊所依賴的其他模塊。使用modprobe命令加載的模塊若以“modprobe -r filename”的方式卸載將同時卸載其依賴的模塊甘有。++

++使用modinfo<模塊名>命令可以獲得模塊的信息诉儒,包括模塊作者、模塊說明亏掀、模塊所支持的參數(shù)以及vermagic++忱反。

# modinfo hello.ko
   filename:      hello.ko
   alias:         A simplest module
   description:    A simple Hello world module
   license:       Dual BSD/GPL
   author:        Aaron konishi:zh5202@163.com
   srcversion:     3FE9B0FBAFDD565399B9C05
   depends:
   vermagic:      2.6.15-11-generic SMP mod_unload modversions 586

二、Linux內(nèi)核模塊詳解

2.1 模塊加載函數(shù)

++Linux內(nèi)核模塊加載函數(shù)一般以__init標識聲明++滤愕,典型的模塊加載函數(shù)的形式如代碼清單1.2所示温算。

代碼清單1.2 內(nèi)核模塊加載函數(shù)

static int __init initialization_function(void)
{
    /* 初始化代碼 */
}
module_init(initialization_function);

==模塊加載函數(shù)必須以“module_init(函數(shù)名)”的形式被指定==。它返回整型值间影,若初始化成功則返回0注竿;初始化失敗則返回錯誤編碼。在Linux內(nèi)核里魂贬,錯誤編碼是一個負值巩割,在<linux/errno.h>中定義,包含-ENODEV付燥、-ENOMEM之類的符號值宣谈。總是返回相應(yīng)的錯誤編碼是種非常好的習慣机蔗,因為只有這樣蒲祈,用戶程序才可以利用perror等方法把它們轉(zhuǎn)換成有意義的錯誤信息字符串。

在Linux 2.6內(nèi)核中萝嘁,可以++使用request_module(const char *fmt,…)函數(shù)加載內(nèi)核模塊++梆掸,驅(qū)動開發(fā)人員可以通過調(diào)用:

request_module(module_name);

或:

request_module(“char-major-%d-%d”, MAJOR(dev), MINOR(dev));

這種靈活的方式加載其他內(nèi)核模塊。

在Linux中牙言,所有標識為__init的函數(shù)在鏈接的時候都放在.init.text這個區(qū)段內(nèi)酸钦,此外,所有的__init函數(shù)在區(qū)段.initcall.init中還保存了一份函數(shù)指針咱枉,在初始化時內(nèi)核會通過這些函數(shù)指針調(diào)用這些__init函數(shù)卑硫,并在初始化完成后,釋放init區(qū)段(包括.init.text蚕断、.initcall.init等)欢伏。

2.2 模塊卸載函數(shù)

++Linux內(nèi)核模塊卸載函數(shù)一般以__exit標識聲明++,典型的模塊卸載函數(shù)的形式如代碼清單1.3所示亿乳。

代碼清單1.3 內(nèi)核模塊卸載函數(shù)

static void __exit cleanup_function(void)
{
    /* 釋放代碼 */
}
module_exit(cleanup_function);

模塊卸載函數(shù)在模塊卸載的時候執(zhí)行硝拧,不返回任何值,++必須以“module_exit(函數(shù)名)”的形式來指定++葛假。

通常來說障陶,模塊卸載函數(shù)要完成與模塊加載函數(shù)相反的功能,如下所示:

  • 若模塊加載函數(shù)注冊了xxx聊训,則模塊卸載函數(shù)應(yīng)該注銷xxx抱究;
  • 若模塊加載函數(shù)動態(tài)申請了內(nèi)存,則模塊卸載函數(shù)應(yīng)釋放該內(nèi)存带斑;
  • 若模塊加載函數(shù)開啟了硬件鼓寺,則模塊卸載函數(shù)中一般要關(guān)閉該硬件;
  • 若模塊加載函數(shù)申請了硬件資源(中斷勋磕、DMA通道侄刽、I/O端口和I/O內(nèi)存等)的占用,則模塊卸載函數(shù)應(yīng)釋放這些硬件資源朋凉;

和__init一樣州丹,__exit也可以使對應(yīng)的函數(shù)在運行完成后自動回收內(nèi)存。實際上杂彭,__init和__exit都是宏墓毒,其定義分別為:

#define __init  __attribute__ ((__section__(“.init.text”)))
#define MODULE
#define __exit  __attribute__ ((__section__(“.exit.text”)))
#else
#define __exit  __attribute_used__attribute__ ((__section__(“.exit.text”)))
#endif

數(shù)據(jù)也可以被定義為__initdata和__exitdata,這兩個宏分別為:

#define __initdata  __attribute__ ((__section__(“.init.data”)))
#define __exitdata  __attribute__ ((__section__(“.exit.data”)))

2.3 模塊參數(shù)

我們可以++用“module_param(參數(shù)名,參數(shù)類型,參數(shù)讀/寫權(quán)限)”為模塊定義一個參數(shù)++亲怠,例如下列代碼定義了1個整型參數(shù)和1個字符指針參數(shù):

static char *book_name = “dissecting Linux Device Driver”;
static int num = 4000;
module_param(num, int, S_IRUGO);
module_param(book_name, charp, S_IRUGO);

++在裝載內(nèi)核模塊時所计,用戶可以向模塊傳遞參數(shù),形式為“insmod(或modprobe) 模塊名 參數(shù)名=參數(shù)值”团秽,如果不傳遞主胧,參數(shù)將使用模塊內(nèi)定義的缺省值++叭首。

參數(shù)類型可以是byte、short踪栋、ushort焙格、int、uint夷都、long眷唉、ulong、charp(字符指針)囤官、bool或invbool(布爾的反)冬阳,在模塊被編譯時會將module_param中聲明的類型與變量定義的類型進行比較,判斷是否一致党饮。

模塊被加載后肝陪,在/sys/module/目錄下將出現(xiàn)以此模塊名命名的目錄。當“參數(shù)讀/寫權(quán)限”為0時刑顺,表示此參數(shù)不存在sysfs文件系統(tǒng)下對應(yīng)的文件節(jié)點见坑,如果此模塊存在“參數(shù)讀/寫權(quán)限”不為0的時,在此模塊的目錄下將會出現(xiàn)parameters目錄捏检,包含一系列以參數(shù)名命名的文件節(jié)點荞驴,這些文件的權(quán)限值就是傳入module_param()的“參數(shù)讀/寫權(quán)限”,而文件的內(nèi)容為參數(shù)的值贯城。

除此之外熊楼,++模塊也可以擁有參數(shù)數(shù)組,形式為“module_param_array(數(shù)組名, 數(shù)組類型, 數(shù)組長度, 參數(shù)讀/寫權(quán)限)”++能犯。從2.6.0~2.6.10版本鲫骗,需將數(shù)組長變量名賦給“數(shù)組長”,從2.6.10版本開始踩晶,需將數(shù)組長變量的指針賦給“數(shù)組長”执泰,當不需要保存實際輸入的數(shù)組元素個數(shù)時,可以設(shè)置“數(shù)組長”為NULL渡蜻。

運行insmod或modprobe命令時术吝,應(yīng)使用逗號分隔輸入的數(shù)組元素。

現(xiàn)在我們定義一個包含兩個參數(shù)的模塊(如代碼清單1.4)茸苇,并觀察模塊加載時被傳遞參數(shù)和不傳遞參數(shù)時的輸出排苍。

代碼清單1.4 帶參數(shù)的內(nèi)核模塊

#include <linux/init.h>
#include <linux/module.h>
static char *book_name = “dissecting Linux Device Driver”;
static int num = 4000;
static int book_init(void)
{
    printk(KERN_INFO”book name:%s\n”, book_name);
    printk(KERN_INFO”book num:%d\n”, num);
    return 0;
}
static void book_exit(void)
{
    printk(KERN_INFO”book module exit\n”);
}
module_init(book_init);
module_exit(book_exit);
module_param(num, int, S_IRUGO);
module_param(book_name, charp, S_IRUGO);
MODULE_AUTHOR(“Aaron Konishi<zh5202@163.com>”);
MODULE_DESCRIPTION(“A simple Module for testing module params”);
MODULE_VERSION(“V1.0”);
MODULE_LICENSE(“Dual BSD/GPL”);

對上述模塊運行“insmod book.ko”命令加載,相應(yīng)輸出都為模塊內(nèi)的默認值学密,通過查看“/var/log/messages”日志文件可以看到內(nèi)核的輸出:

# tail -n 2 /var/log/messages
Jul 2 01:03:10 localhost kernel: <6> book name:dissecting Linux Device Driver
Jul 2 01:03:10 localhost kernel: <6> book num:4000

當用戶運行“insmod book.ko book_name=’GoodBook’ num=5000”命令時淘衙,輸出的是用戶傳遞的參數(shù):

# tail -n 2 /var/log/messages
Jul 2 01:03:10 localhost kernel: <6> book name:GoodBook
Jul 2 01:03:10 localhost kernel: <6> book num:5000

2.4 模塊符號導出

Linux 2.6的“/proc/kallsyms”文件對應(yīng)著內(nèi)核符號表,它記錄了符號以及符號所在的內(nèi)存地址腻暮。模塊可以使用如下宏導出符號到內(nèi)核符號表:

EXPORT_SYMBOL (符號名);
EXPORT_SYMBOL_GPL(符號名);

導出的符號將可以被其他模塊使用彤守,使用前聲明一下即可毯侦。EXPORT_SYMBOL_GPL()只適用于包含GPL許可權(quán)的模塊。代碼清單1.5給出了一個導出整數(shù)加具垫、減運算函數(shù)符號的內(nèi)核模塊的例子(這里僅僅是為了演示)侈离。

代碼清單1.5 內(nèi)核模塊中的符號導出

#include <linux/init.h>
#include <linux/module.h>
int add_integar(int a,int b);
{
    return a+b;
}
int sub_integar(int a,int b)
{
    return a-b;
}
EXPORT_SYMBOL(add_integar);
EXPORT_SYMBOL(add_integar);
MODULE_LICENSE(“Dual BSD/GPL”);

加載該模塊之后,從“/proc/kallsyms”文件中找出add_integar做修、sub_integar相關(guān)信息:

# cat /proc/kallsyms | grep integar
…..
c886f00 T add_integar [export]
c886f0b T sub_integar [export]
……

2.5 模塊的聲明與描述

在Linux內(nèi)核模塊中霍狰,我們可以用MODULE_AUTHOR抡草、MODULE_DESCRIPTION饰及、MODULE_VERSION、MODULE_DEVICE_TABLE康震、MODULE_ALIAS分別聲明模塊的作者燎含、描述、版本腿短、設(shè)備表和別名屏箍,例如:

MODULE_AUTHOR(author);
MODULE_DESCRIPTION(description);
MODULE_VERSION(version_string);
MODULE_DEVICE_TABLE(table_info);
MODULE_ALIAS(alternate_name);

對于USB、PCI等設(shè)備驅(qū)動橘忱,通常會建立一個MODULE_DEVICE_TABLE赴魁,表明該驅(qū)動模塊所支持的設(shè)備,如代碼清單1.6所示钝诚。

/* 對應(yīng)此驅(qū)動的設(shè)備表 */
static struct usb_device_id skel_table[] = {
    { USB_DEVICE(USB_SKEL_VENDOR_ID,
     USB_SKEL_PRODUCT_ID)  }
    { } /* 表結(jié)束 */
};
MODULE_DEVICE_TABLE(usb, skel_table);

此時颖御,并不需要讀者理解MODULE_DEVICE_TABLE的作用,后續(xù)相關(guān)章節(jié)會有詳細介紹凝颇。

2.6 模塊的使用計數(shù)

Linux 2.4內(nèi)核中潘拱,模塊自身通過MOD_INC_COUNT、MOD_DEC_USE_COUNT宏來管理自己被使用的計數(shù)拧略。

Linux 2.6內(nèi)核提供了模塊計數(shù)管理接口try_module_get(&module)和module_put(&module)芦岂,從而取代Linux 2.4內(nèi)核中的模塊使用計數(shù)管理宏。模塊的使用計數(shù)一般不必由模塊自身管理垫蛆,而且模塊計數(shù)管理還考慮了SMP與PREEMPT機制的映像禽最。

int try_module_get(struct module *module);

該函數(shù)用于增加模塊使用計數(shù),若返回0袱饭,表示調(diào)用失敗弛随,希望使用的模塊沒有被加載或正在被卸載中。

void module_put(struct module *module);

該函數(shù)用于減少模塊使用計數(shù)宁赤。

try_module_get()與module_put()的引入與使用與Linux 2.6內(nèi)核下的設(shè)備模型密切相關(guān)舀透。Linux 2.6內(nèi)核為不同類型的設(shè)備定義了struct module *owner域,用來指向管理此設(shè)備的模塊决左。當開始使用某個設(shè)備時愕够,內(nèi)核使用try_module_get(dev->owner)去增加管理此設(shè)備的owner模塊的使用計數(shù)走贪;當不再使用此設(shè)備時,內(nèi)核使用module_put(dev->owner)減少對管理此設(shè)備的owner模塊的使用計數(shù)惑芭。這樣坠狡,當設(shè)備在使用時,管理此設(shè)備的模塊將不能被卸載遂跟。只有當設(shè)備不再被使用時逃沿,模塊才允許被卸載。

在Linux 2.6內(nèi)核下幻锁,對于設(shè)備驅(qū)動工程師而言凯亮,很少需要親自調(diào)用try_module_get()與module_put(),因為此時開發(fā)人員所寫的驅(qū)動通常與支持某具體設(shè)備的owner模塊哄尔,對此設(shè)備owner模塊的計數(shù)管理由內(nèi)核里更底層的代碼如總線驅(qū)動或是此類設(shè)備共用的核心模塊來實現(xiàn)假消,從而簡化了設(shè)備驅(qū)動的開發(fā)。

2.7 模塊的編譯

我們可以為代碼清單1.1的模板編寫一個簡單的Makefile:

KVERS = $(shell uname -r)
# Kernel modules
obj-m += hello.o
# Specify flags for the module compilation.
#EXTRA_CFLAGS=-g -O0
build: kernel_modules
kernel_modules:
    make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
clean:
    make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean

該Makefile文件應(yīng)該與源代碼hello.c位于同一目錄岭接,開啟其中的EXTRA_CFLAGS=-g -O0可以得到包含調(diào)試信息的hello.ko模塊富拗。運行make命令得到的模塊可直接在PC上運行。

如果一個模塊包括多個.c文件(如file1.c鸣戴、file2.c)啃沪,則應(yīng)該以如下方式編寫Makefile:

obj-m := modulename.o
modulename-objs := file1.o file2.o

2.8 使模塊繞開GPL

對于企業(yè)自己編寫的驅(qū)動等內(nèi)核代碼,如果不編譯為模塊則無法繞開GPL窄锅,編譯為模塊后企業(yè)在產(chǎn)品中使用模塊创千,則公司對外不再需要提供對應(yīng)的源代碼,為了使公司產(chǎn)品所使用的Linux操作系統(tǒng)支持模塊酬滤,需要完成如下工作:

  • 在內(nèi)核編譯時應(yīng)該選上“可以加載模塊”签餐,嵌入式產(chǎn)品一般不需要動態(tài)卸載模塊,所以“可以卸載模塊”不用選盯串;
  • 將我們編譯的內(nèi)核模塊.ko文件放在目標文件系統(tǒng)的相關(guān)目錄中氯檐;
    產(chǎn)品的文件系統(tǒng)中應(yīng)該包含了支持新內(nèi)核的insmod、lsmod体捏、rmmod等工具冠摄,由于嵌入式產(chǎn)品中一般不需要建立模塊間依賴關(guān)系,所以modprobe可以不要几缭,一般也不需要卸載模塊河泳,所以rmmod也可以不要;
  • 在使用中用戶可使用insmod命令手動加載模塊年栓,如insmod xxx.ko拆挥;
  • 但是一般而言,產(chǎn)品在啟動過程中應(yīng)該加載模塊某抓,在嵌入式產(chǎn)品Linux的啟動過程中纸兔,加載企業(yè)自己的模塊的最簡單的方法是修改啟動過程的rc腳本惰瓜,增加insmod /…/xxx.ko這樣的命令。用busybox做出的文件系統(tǒng)汉矿,通常修改/etc/init.d/rcS文件崎坊。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市洲拇,隨后出現(xiàn)的幾起案子奈揍,更是在濱河造成了極大的恐慌,老刑警劉巖赋续,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件男翰,死亡現(xiàn)場離奇詭異,居然都是意外死亡蚕捉,警方通過查閱死者的電腦和手機奏篙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門柴淘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來迫淹,“玉大人,你說我怎么就攤上這事为严×舶荆” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵第股,是天一觀的道長应民。 經(jīng)常有香客問我,道長夕吻,這世上最難降的妖魔是什么诲锹? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮涉馅,結(jié)果婚禮上归园,老公的妹妹穿的比我還像新娘。我一直安慰自己稚矿,他們只是感情好庸诱,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著晤揣,像睡著了一般满葛。 火紅的嫁衣襯著肌膚如雪险绘。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機與錄音柔昼,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的环疼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼朵耕,長吁一口氣:“原來是場噩夢啊……” “哼炫隶!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起阎曹,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤伪阶,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后处嫌,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體栅贴,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年熏迹,在試婚紗的時候發(fā)現(xiàn)自己被綠了檐薯。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡注暗,死狀恐怖坛缕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情捆昏,我是刑警寧澤赚楚,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站骗卜,受9級特大地震影響宠页,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜寇仓,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一举户、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧遍烦,春花似錦俭嘁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蔓姚,卻和暖如春捕虽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背坡脐。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工泄私, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓晌端,卻偏偏與公主長得像捅暴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子咧纠,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

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

  • 周五抽了一張問題卡蓬痒,問題是“有什么是你一直想做卻多年未能著手進行的事”,這個問題是個好問題漆羔,而我卻一下沒有答案梧奢,我...
    祉莉翔媽閱讀 670評論 0 1
  • 父母的日漸衰老是我不得不察覺到的實事,今天冒雨趕往學校了演痒,一種說不出口的復雜情感堵在胸口亲轨,有對家人的不舍,對未來的...
    伊古董閱讀 200評論 0 1
  • 我的駕照拿到快一年了,每當我放著我喜歡的電子音樂讯嫂,在高速上飛奔的時候蹦锋,我就會想起這一年的生活,我的大學生活端姚。其實并...
    tonytonie閱讀 469評論 0 0
  • 純白的愛人天各一方晕粪, 默守陳規(guī)到夕陽挤悉, 與雛鳥交談同頑石幻想渐裸, 逃出圓形立方的不只我一個模樣。 晨曦清唱装悲, 半夜哽...
    果間房的晚餐閱讀 308評論 1 7