《 第三章 寄存器 》

这一章节中,就通过 debug 的方式来对寄存器中的内容进行操作,如果你想提前试试汇编指令,
可以翻到最后一小节,熟悉下汇编指令之后,再去分析每条指令执行之后各个寄存器的值。

一个典型的 CPU由运算器控制器寄存器等器件构成,这些器件靠内部总线相连。前面所说的总线,相对于 CPU 而言是外部总线。内部总线实现 CPU 内部各个器件之间的联系,外部总线实现 CPU 和 主板其他器件的联系。
在CPU中:

  • 运算器进行信息处理;
  • 寄存器进行信息存储;
  • 控制器控制各种器件进行工作;
  • 内部总线连接各种器件,在它们之间进行数据的传送

对于一个汇编程序员来说,CPU中的主要部件是寄存器。寄存器是CPU中程序员可以用指令读写的部件。
程序员通过改变各种寄存器中的内容来实现对CPU的控制。

不同的CPU,寄存器个数、结构不同。 8086 CPU有 14 个寄存器,每个寄存器都有一个名称。这些寄存器是:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW。

3.1 通用寄存器

8086CPU 的所有寄存器都是 16 位的,可以存放两个字节。
AX、BX、CX、DX 这 4 个寄存器通常用来存放一般性的数据,被称为通用寄存器。

以 AX 为例,寄存器的逻辑结构如图 3-1 所示:


图 3-1

一个 16 位寄存器可以存储一个 16 位的数据,数据在寄存器中存储情况如图 3-2 所示.

思考一下,一个 16 位寄存器所能存放的数据最大值为多少?

答: 2^16 - 1 = 65535 (0 ~ 65535 ,共65536个数字)

8086CPU的上一代CPU中寄存器都是 8 位,为了保证兼容,是原来基于上一代CPU编写的程序稍加修改就可以运行在8086之上,8086CPU 的AX、BX、CX、DX这 4 个寄存器都可分为两个独立使用的 8 位寄存器来用:

  • AX 可分为 AH 和 AL;
  • BX 可分为 BH 和 BL;
  • CX 可分为 CD 和 CL;
  • DX 可分为 DH 和 DL;
图 3-2

以 AX 为例, 8086CPU 的16位寄存器可分为两个8位寄存器情况如图 3-3 所示:


图 3-3

AX 的低 8 位(0~7位)构成了 AL 寄存器,高8位(8~15)构成了AH寄存器。AL和AH都可以独立使用8位寄存器。
图 3-4 展示了 16 位寄存器及它所分成的两个 8 为寄存器的数据存储情况。


图 3-4

思考一下,一个 8 位寄存器所能存储的数据的最大值为多少?

答: 2 ^ 8 - 1= 255 (0~255,共 256个不同数字)

3.2 字在寄存器中的存储

出于对兼容性的考虑, 8086CPU可以一次性处理两种尺寸的数据。

  • 字节:记为 byte, 一个字节由 8 个 bit 组成,可以存储在 8 位寄存器中;
  • 字:记为 word, 一个字由两个字节组成,这两个字节分别称为这个字的高位字节和低位字节, 如图 3-5 所示


    图 3-5

一个字可以存储在一个 16 位寄存器总,这个字的高位字节和低位字节自然就存储在这个寄存器高8位寄存器和低8位寄存器中。
如图 3-4 所示,一个字型数据 2000, 存储在 AX 寄存器中,在 AH 中存储了它的高 8 位,在 AL 中存储了它的低 8 位。 AH 和 AL 中的数据,既可以看成是一个字型数据的高 8 为和低 8 位,这个字型数据的大小是: 20000; 又可以看成是两个独立的字节型数据,它们的大小分别是 78 和 32。

3.3 关于数制的讨论

任何数据,到了计算机中都是以二进制形式存放的。为了描述不同的问题,又经常将它们用其他的进制来表示。比如图 3-4 中寄存器 AX 中的数据是 0100111000100000, 这就是 AX 中信息本身,可以用不同的逻辑意义来看待它。可以将它看做一个数值,大小是 20000。

当然, 二进制数 0100111000100000 本身也可以表示一个数值的大小,但是人类习惯于十进制,用十进制20000表示可以使我们直观地感受这个数值的大小。

十六进制数的一位相当于二进制数的四位, 如 0100111000100000 可表示成: 4(0100)、E(1110)、2(0010)、0(0000) 四个十六进制数。

由于一个内存单元可存放 8 位数据,CPU 中的寄存器又可存放 n 个 8 位数据。也就是说,计算机中的数据大多是由 1~N个 8 位数据构成。很多时候,需要直观地看出组成数据的各个字节数据的值,用十六进制来表示数据可以直观的看出这个数据由哪些 8 为数据构成的。

比如, 20000 写成 4E20 就可以了直观的看出这个数据由 4E 和 20 两个 8 为数据构成,如果AX中存放4E20,则 AH 存放的是 4E, AL存放的是 20。这种方式表示数据便于直观地分析问题,我们多用十六进制来表示一个数据。

在以后的课程中,为了区分不同的进制,在十六进制表示的数据后面加 H,二进制后面加 B,十进制不加。
例如:
十进制: 20000
十六进制:4E20
二进制: 0100111000100000B

3.4 几条汇编指令

这小节主要分析寄存器中的值,可以先看后面的实验,然后通过汇编指令去验证
通过汇编指令控制CPU进行工作中,如图 3-6 中几条指令


图 3-6

汇编指令不区分大小写。

接下来看些汇编指令,执行完后,各个寄存器中数据的变化:
如图 3-7


image.png

程序段最后一条指令 add ax,bx, 在执行前 ax 和 bx 中的数据都为 8226H。
相加之后所得值: 1044CH ,但是 ax 为 16 为寄存器,只能存放 4 位十六进制数据,所以高位 1 不能再 ax 中保存,ax 中的数据为: 044CH。

图 3-8

程序最后一条指令 add al,93H, 在执行前,al 中的数据为 C5H,相加后所得的值为 158H,但是 al 为 8 位寄存器,只能存放十六进制的数据,所以最高位的 1 丢失,ax 中的数据为: 0058H。
注意,这里的al是作为一个独立的 8 位寄存器来使用和 ah 没有关系,CPU 在执行这条指令时认为 ah 和 al 是两个不相关的寄存器。不要错误的认为, add al,93H 指令产生的进位会存储到 ah 中,add al,93H 是进行的 8 位运算。
如果执行 add ax,93H, 低 8 位的进位会存储在 ah 中, CPU 在执行这条执行时认为只有一个 16 位 寄存器 ax,进行的是 16 位运算。指令 add ax,93H 执行后,ax 中的值为: 0158H。此时,使用的寄存器是 16 位寄存器ax, add ax,93H 相当于将 ax 中的 16 位数据 00c5H 和 另一个 16 位数据 0093H 相加,结果是 16 位的 0158H。
注意:
在进行数据传送或者运算时,要注意指令的两个操作对象的位数应当一致

mov ax,bx
mov bx,cx
mov ax,18H
mov al, 18H
add ax,bx
add ax,20000

上面这些指令都是正确的,而

mov ax,bl
mov bh,al
mov al,20000
add al,100H

这些指令都是错误的,原因都是指令的两个操作对象位数不一致。

3.5 物理地址

我们知道,CPU 访问内存单元时,要给出内存单元的地址。所有的内存单元构成存储空间是一个一维的线性空间,每一个内存单元在这个空间中都有唯一的地址,我们将这个唯一的地址称为物理地址。

CPU 通过地址总线送入存储器的,必须是一个内存单元的物理地址。在 CPU 向地址总线发出物理地址之前,必须要在内部先形成这个物理地址。不同的CPU可以有不同的形成物理地址的形式。这里讨论 8086CPU是如何在内部形成内存单元的物理地址。

3.6 16 位机结构的CPU

什么是 16 位结构的CPU呢?

  • 运算器一次最多可处理 16 位的数据
  • 寄存器的最大宽度为 16 位
  • 寄存器和运算器之间的通路为 16 位
    8086 是 16 位结构的CPU,也就是说,在 8086 内部,能够一次性处理、传输、暂存的信息最大长度是 16 位。内存单元的地址在送上地址总线之前,必须在 CPU 中处理、传输和暂存,对于 16 位 CPU,能一次性处理、传递和暂存的 16 位的地址。

3.7 8086CPU 给出物理地址的方法

8086CPU 有 20 位地址总线,可以传送 20 位地址,达到 1 MB 寻址能力。
8086CPU 又是 16 位结构,在内部一次性处理、传输、暂存地址为 16 为。从 8086CPU 的内部结构来看,如果将地址从内部简单发出去,那么它只会形成 16 位地址,表现出的寻址能力是 64KB。
为了形成 20 位物理地址,达到 1 MB 的物理寻址能力,8086CPU 采用一种在内部用两个 16 位地址合成的方法来形成一个 20 位的物理地址。


图 3-9

如图 3-9, 当 8086CPU 要写内存时:

1) CPU 中相关部件提供两个 16 位的地址,一个称为段地址,另一个称为偏移地址;
2)段地址和偏移地址通过内部总线进入一个称为地址加法器的部件;
3)地址加法器将两个 16 地址合成一个 20 为的物理地址;
4)地址加法器通过内部总线将 20 位物理地址送入输入输出控制电路
5)输入输出控制电路将 20 位物理地址送上地址总线
6)20 位物理地址被地址总线传送到存储器

地址加法器采用物理地址=段地址x16 + 偏移地址的方法用段地址和偏移地址合成物理地址。
例如, 8086CPU 要访问地址为 123C8H的内存单元,此时,地址加法器的工作过程如下:

3.8 “段地址 x16 + 偏移地址 = 物理地址” 本质含义

本质含义:CPU 在访问内存时,用一个基础地址(段地址x16) 和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址。也就是说 8086CPU 的这种寻址功能是 “基础地址+偏移地址=物理地址”寻址模式的一种具体实现方案。 8086CPU中,段地址x16可看做是基础地址。

3.9 段的概念

3.10 段寄存器

3.11 CS 和IP

3.12 修改 CS 、 IP 的指令

3.13 代码段

实验1 查看 CPU 和 内存,用机器指令和汇编指令编程


1. 预备知识: Debug 的使用

  • 什么是 Debug?
    Debug 是 DOS、Windows 都提供的程序调试工具(8086)。使用它可以查看 CPU 个中寄存器中的内容、内存情况和在机器码级跟踪程序运行。

  • 常用Debug功能

    • R 命令查看和改变CPU寄存器的内容;
    • D 命令查看内存中的内容;
    • E 命令改写内存中的内容;
    • U 命令将内存中的机器指令翻译成汇编指令;
    • T 命令执行一条机器指令;
    • A 命令以汇编指令的格式在内存中写入一条机器指令

Debug 命令比较多,总共 20 多个,这 6 个是和汇编密切相关的。

2. Debug 模式开启

这里使用的是 DOSBox 0.74


image.png

全屏:option + enter, 退出全屏 option + enter

3. 用 R 命令查看、改变 CPU 寄存器内容

我们先查看下 AX 、 BX 、 CX 、 DX 、CS 、IP 这 6 个寄存器内容,其他的暂时忽略。


image.png

注意 CS 和 IP 的值, CS=073F, IP = 0100,也就是说,内存 073F:0100处的指令为 CPU 当前要读取、执行的指令。在所有寄存器的下方, Debug 还列出了 CS:IP 所指向的内存单元出所存放的机器码,并将它翻译为汇编指令。
可以看到,CS:IP所指向的内存单元为 073F:0100,此处存放的机器码为 198B1E52 对应的汇编指令为 SBB [BP + DI +521E], CX 。暂时先看这些,其他指令自行忽略。

除了查看寄存器的内容之外,还可以修改寄存器的内容:


image.png

若要修改一个寄存器中的值,比如 AX 中的值,可用 R 命令后加寄存器的名来进行,输入 r ax 后回车,将出现 “:”作为输入提示,在后面输入要写入的数据后,enter 完成,即完成了对 AX 中内容的修改。若想要再次查看AX中的内容,可再用 R 命令查看。如图所示:


image.png

在 上图中,一旦进入DEBUG,用 R 命令查看,CS:IP 指向 073F:0100,此处存放的机器码为 07,对应的汇编指令 POP ES;
接着,用 R 命令将 IP 修改为 200, 则 CS:IP 指向 073F:0200,此处存放的机器码为 C27529 对应的汇编指令:RET 2975;
接着,用 R 命令修改CS为 ff00, 则 CS:IP 指向 ff00:0200, 此处存放的机器码为 000 对应的汇编指令 ADD [BX+SI], AL;

4. 用 D 命令查看内存中的内容

D 命令可以查看内存中的内容。如果我们想知道内存 10000H 处的内容,可以用 'd 段地址:偏移地址' 格式来查看


image.png

要查看内存 10000H 处的内容 ,首先将这个地址表示为段地址:偏移地址的格式,可以是 1000:0,然后用 ’d 1000:0 ' 列出 1000:0 处的内容。
使用 D 命令, Debug 将输出 3 部分内容:

  • 中间部分是从指定地址开始的 128(8行 16 列) 个内存单元的内容用十六进制的格式输出,每行的输出从 16 的整数倍的地址开始,最多输出 16 个单元的内容。从图中,可以知道内存 1000:0 单元中的内容是 92H,1000:1 单元中的内容是 B2H,内存 1000:0~1000:F中的内容都在第一行;内存 1000:10 中的内容是 00H, 内存 1000:11 中的内容是 40H,内存 1000:10~1000:1F 中的内容都在第二行。注意,每行的中间有一个 “-”,它将每行的输出分为两部分,在“-”前后各8个单元,这样便于查找。比如寻找 1000:6B 单元中的内容,我们知道第 7 行,然后从中间的“-”向后树 3 个单元内容 0AH。(这一部分内容,每一句都要对着上面的图进行查看)
  • 左边是每行的起始地址。
  • 右边是每个内存单元中数据对应的可现实的ASCII码字符。比如,第一行 1000:11, 1000:1C, 1000:7D 中存放的数据是 40H、38H、21H,它们对应的ASCII字符分别是 @, 8, !。而 1000:0 内存单元,92H没有对应的可可显示 ASCII 字符,Debug就用 “.”来代替。
    注意,我们看到的内存中的内容,在不同的计算机中是不一样的,也可能每次用Debug看到的内容都不同,因为我们用Debug看到的都是原来就在内存中个的内容,这些内容受随时都可能变化的系统环境的影响。当然,我们也可以改变内存、寄存器中的内容。

我们使用 d 1000:9 查看 1000:9 处的内容,Debug将怎样输出呢?如图所示:


查看 1000:9 处的内容

Debug 从 1000:9 开始显示,一直到 1000:88 ,一共显示 128 个字节。第一行 1000:0~1000:8 单元中的内容不显示。

在一进入 Debug 后,用 D 命令直接查看,将列出 Debug 预设的地址处的内容 如图所示


列出 Debug 预设的地址处内容

在使用了 “d 段地址:偏移地址”之后,接着使用 D 命令,可列出后续内容,如图:


列出后续内容

也可以指定 D 命令查看范围,此时采用 “d 段地址: 起始偏移地址 结尾偏移地址”格式。比如要查看 1000:0 ~ 1000:9 中的内容,可以用 “d 1000: 0 9" 实现


查看 1000:0 ~ 1000:9 单元中的内容

如果我们想查看内存单元 10000H 中的内容,可以用如下的方式中任意一种:


用 3 种不同的段地址和偏移地址查看同一个物理地址内容
  • 用 Debug 的 E 命令改写内存中的内容
    可以使用 E 命令来改写内存中内容,比如,要将内存 1000:0~1000:9 单元中的内容分别写成 0、1、2、3、4、5、6、7、8、9,可以用 "e 起始地址 数据 数据 数据 ... ..." 格式来进行


    用 E 命令修改从 1000:0 开始的 10 个单元的内容

也可以采用提问的方式来一个一个地改写内存中的内容


用 E 命令修改从1000:10 开始的三个单元的内容

上面的操作步骤为:

  1. 输入 e 1000:10, enter
  2. 屏幕显示其实地址 1000:10 和第一个单元(1000:0010 单元)的原始内容,然后光标停在 "." 后面提示要输入的数据,此时可以有两个选择:输入数据,然后空格继续输入下一个单元;其二不输入数据,直接空格,则不修改当前内存单元内容
  3. 所有内存单元修改完毕之后,enter 结束 E 命令操作。

可以用 E 命令向内存单元中写入字符,比如,用 E 命令从内存 1000:0 开始写入数值 1、 字符‘a’、数值 2、字符'b'、数值 3 、字符 'c',可采用如下方法进行:


用 E 命令向内存中写入字符

从图中可以看出, Debug 对 E 命令执行的结构是, 向 1000:0, 1000:2, 1000:4 单元中写入数值 1、2、3,向 1000:1 、 1000:3 、1000:5 单元中写入字符 'a', 'b','c' 的ASCII 码值: 61H、62H、63H。
也可以用E命令向内存中写入字符串,比如用E命令从内存 1000:0 开会写入: 数值 1, 字符串'a+b', 数值 2、 字符串 'C++'、字符 3 、字符串 'IBM'.


用E命令向内存中写入字符串
  • 用 E 命令向内存中写入机器码,用 U 命令查看内存中机器码的含义,用 T 命令执行内存中的机器码。
    如何向内存中写入机器码呢?
    我们知道,机器码也是数据,当然可以用 E 命令将机器码写入内存。比如我们要从内存 1000:0 单元开始写入这样一段机器码:
b80100 mov ax, 0001
b90200 mov cx, 0002
01c8     add  ax, cx
E 命令将机器码写入内存 & U 命令将内存单元内容翻译成汇编指令显示

U 命令的显示输出分为 3 部分
1) 每一条机器指令的地址;
2)机器指令
3)机器指令所对应的汇编指令

我们可以看到:
1000: 0 地址单元存放的是写入的机器码 b8 01 00 所组成的机器指令,对应的汇编指令是 mov ax,0001;
1000: 3 地址单元存放的是写入的机器码 b9 02 00 所组成的机器指令,对应的汇编指令是 mov cx,0002;
1000: 6 地址单元存放的是写入的机器码 01 c8 所组成的机器指令,对应的汇编执行是 add ax, cx;
由此,我们可以再一次看到内存中的数据和代码没有任何区别,关键在于如何解释。

如何执行我们写入的机器指令呢?使用 Debug 的 T 命令可以执行一条或者多条指令,简单第使用 T 命令可以执行 CS:IP 指向的指令,如图:


T 命令执行 CS:IP 指向的指令

首先,通过E命令向内存单元 1000:0 开始写入了 6 个字节的机器码,然后通过 R 命令查看 CPU 寄存器中的状态,可以看到CS=073F IP=0100,指向内存:073f:0100;如要 T 命令控制 CPU 执行我们写到 1000:0 的指令,必须先让 CS:IP 指向 1000:0 ,所以我们通过 R 命令 修改 CS 和 IP 中的内容,使 CS:IP 指向 1000:0。
完成上面的步骤之后,就可以了用 T 命令来执行我们写入的指令了(此时, CS:IP 指向我们的指令所在的单元)。执行 T 命令之后,CPU 执行 CS:IP 指向的指令,则 1000:0 处的指令 b8 01 00(mov ax,0001)得到执行,执行指令后,Debug 显示寄存器的状态
注意, 指令执行后,AX 中的内容被改写为 1, IP 改变为 IP+3(因为 mov ax,0001 的指令长度是 3 个字节), CS:IP 指向下一条指令。
我们可以继续使用T命令,指向下面的指令


用 T 命令继续执行

如上图所示,用 T 命令继续执行后面的指令,注意每条指令执行后,CPU 相关寄存器的变化。

  • Debug 的 A 命令以汇编指令的形式在内存中写入机器指令
    前面我们使用 E 命令写入机器指令,这样很不方便,最好能直接以汇编指令的形式写入指令。为此 Debug 提供了 A 命令。 A 命令使用方法如下:


    用 A 命令向从 1000:0 开始的内存单元中写入指令

先用 A 命令,以汇编语言向从 1000:0 开始的内存单元写入几条指令,然后用 D 命令查看 A 命令执行之后的结果。可以看到,在使用 A 命令写入指令时,我们输入的是汇编执行,debug 将这些汇编指令翻译成对应的机器指令,将它们的机器执行写入内存。
使用 A 命令写入汇编指令时,在给出的起始地址后直接按 enter 表示操作结束

简单地用 A 命令,从一个预设的地址开始输入指令:


从一个预设的地址开始输入指令

执行预设地址中的指令:


image.png
本次实验中用到的命令:
1. 查看和修改CPU中寄存器的内容: R 命令;
2. 查看内存中的内容: D 命令
3. 修改内存中的内容: E命令(可以写入数据、指令,在内存中它们没有区别)
4. 将内存中的内容解释为机器指令和对应的汇编指令: U 命令
5. 执行 CS:IP 指向的内存单元除的指令: T 命令
6. 以汇编指令的形式向内存中写入指令: A 命令
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容