Skip to content

Commit efab8f6

Browse files
committed
update highlight
1 parent 7089161 commit efab8f6

File tree

19 files changed

+360
-360
lines changed

19 files changed

+360
-360
lines changed

content/09-datastruct-algorithm/04-string.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ tags: ["数据结构", "算法", "字符串"]
7070
- 如果 j > T.length, 则当前串匹配成功,返回第一个字符的位置即 i - T.length
7171

7272

73-
{{< highlight cpp >}}
73+
```c++
7474
int Index(SString S, SString T) {
7575
int i = 1, j = 1;
7676
while(i <= S.length && j <= T.length) {
@@ -88,7 +88,7 @@ int Index(SString S, SString T) {
8888
return -1;
8989
}
9090
}
91-
{{< /highlight >}}
91+
```
9292
9393
## 匹配问题-KMP算法
9494
@@ -114,7 +114,7 @@ int Index(SString S, SString T) {
114114
- 第三个字符及之后的,在不匹配的位置前边,划一根美丽的分界线模式串一步步往后退,直到分界线之前能对上,此时j指向哪儿,next数组值就是多少
115115
116116
117-
{{< highlight cpp >}}
117+
```c++
118118
void get_next(SString T, int next[]) {
119119
int i = 1, j = 0;
120120
next[1] = 0;
@@ -128,4 +128,4 @@ void get_next(SString T, int next[]) {
128128
}
129129
}
130130
}
131-
{{< /highlight >}}
131+
```

content/09-datastruct-algorithm/06-graph.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ tags: ["数据结构", "算法", "图"]
351351

352352
### 代码实现
353353

354-
{{< highlight cpp >}}
354+
```c++
355355
// ... 准备工作,根据图的信息初始化矩阵 A 和 path,入上图
356356
for(int k = 0; k < n; k++) {
357357
for(int i = 0; i < n; i++) {
@@ -363,7 +363,7 @@ for(int k = 0; k < n; k++) {
363363
}
364364
}
365365
}
366-
{{< /highlight >}}
366+
```
367367

368368
tips:
369369

content/11-operating-system/03-interprocess-communication.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,31 +28,31 @@ tags: ["os", "操作系统"]
2828

2929
匿名管道用`pipe`函数创建,返回0表示成功,返回-1表示出错。入参传入两个文件描述符,成功后,`fd[0]`用来读,`fd[1]`用来写。后续的UNIX版本支持全双工管道,即,两个文件描述符都可以用来读写
3030

31-
{{< highlight c >}}
31+
```c
3232
#include <unistd.h>
3333
int pipe(int fd[2]);
34-
{{< /highlight >}}
34+
```
3535
3636
某些系统提供全双工管道:SVR4的`pipe`函数以及很多内核提供的`socketpair`函数。全双工管道的实现如图,是两个独立的数据流,即两个半双工的管道组成的
3737
3838
![](https://gitcode.net/xnzone/solar/-/raw/master/2022/02/14104215.png)
3939
4040
标准I/O提供了两个函数`popen`和`pclose`,创建一个管道并启动另外一个进程,该进程要么从该管道读出标准输入,要么往该管道写入标准输出
4141
42-
{{< highlight c >}}
42+
```c
4343
#include <stdio.h>
4444
FILE *popen(const char* command, const char* type); // 成功返回一个文件指针,失败返回NULL
4545
int pclose(FILE *stream); // 出错为-1
46-
{{< /highlight >}}
46+
```
4747

4848
匿名管道在不考虑文件描述符传递时,只能用于亲缘关系的IPC通道,而FIFO是UNIX实现的一个有名管道,是先进先出的模式,同样也是一个半双工管道,但是每一个管道都有一个名称,FIFO管道由`mkfifo`函数创建
4949

50-
{{< highlight c >}}
50+
```c
5151
#include <sys/types.h>
5252
#include <sys/stat.h>
5353

5454
int mkfifo(const char* pathname, mode_t mode); // 成功为0, 错误为-1
55-
{{< /highlight >}}
55+
```
5656
5757
FIFO管道(有名管道),只能用来读或者写,因为它是一个半双工管道
5858
@@ -94,15 +94,15 @@ System V消息队列函数组说明
9494
9595
共享内存主要是通过`mmap`, `munmap`和`msync`函数来实现的
9696
97-
{{< highlight c >}}
97+
```c
9898
#include <sys/mmap.h>
9999
100100
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset); // 成功返回映射区起始地址,失败为MAP_FAILED
101101
102102
int munmap(void *addr, size_t len); // 成功为0,失败为-1
103103
104104
int msync(void *addr,size_t len,int flags); // 成功则为0,出错则为−1
105-
{{< /highlight >}}
105+
```
106106

107107
共享内存,一旦内存映射了一个文件,我们就不再使用read、write和lseek来访问该文件,而只是存取已由mmap映射到该文件的内存位置。把显式的文件I/O操作变换成存取内存单元往往能够简化我们的程序,有时候还能改善性能
108108

content/11-operating-system/04-mutual-synchronization.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ tags: ["os", "操作系统"]
1818
### Peterson算法
1919
Peterson算法的主要代码结构如下
2020

21-
{{< highlight c >}}
21+
```c
2222
#define FALSE 0
2323
#define TRUE 1
2424
#define N 2 /* 进程数量 */
@@ -37,7 +37,7 @@ void enter_region(int process) { /* 进程是0或者1 */
3737
void leave_region(int process) {
3838
interested[process] = FALSE;
3939
}
40-
{{< /highlight >}}
40+
```
4141
4242
主要解决了两个进程之间互斥的问题,用一个`turn`变量来表明是谁的轮次。在使用共享变量(即进入其临界区)之前,各个进程使用其进程号0或1作为参数来调用enter_region。该调用在需要时将使进程等待,直到能安全地进入临界区。在完成对共享变量的操作之后,进程将调用leave_region,表示操作已完成,若其他的进程希望进入临界区,则现在就可以进入。
4343

content/12-xv6-lab/01-cover.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,22 @@ xv6 is a teaching operating system developed in the summer of 2006, which we por
1818
## xv6 sources and text
1919

2020
The latest xv6 source and text are available via
21-
{{< highlight bash >}}
21+
```bash
2222
git clone git://github.com/mit-pdos/xv6-riscv.git
23-
{{< /highlight >}}
23+
```
2424

2525
and
2626

27-
{{< highlight bash >}}
27+
```bash
2828
git clone git://github.com/mit-pdos/xv6-riscv-book.git
29-
{{< /highlight >}}
29+
```
3030

3131
## Develop
32-
{{< highlight bash >}}
32+
```bash
3333
git clone https://pdos.csail.mit.edu/6.828/2018/jos.git
34-
{{< /highlight >}}
34+
```
3535

36-
{{< highlight bash >}}
36+
```bash
3737
docker build -t xv6 .
3838
bash start.sh
39-
{{< /highlight >}}
39+
```

content/12-xv6-lab/lab0-envs/01-env.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ QEMU使用
4848
- `info registers` 显示所有内部寄存器状态,包括隐藏段信息的机器码,中断描述符表,和任务寄存器
4949

5050
比如下面的显示
51-
{{< highlight text >}}
51+
```text
5252
cs =0008 10000000 ffffffff 10cf9a00 DPL=0 CS32 [-R-]
53-
{{< /highlight >}}
53+
```
5454

5555
1. **cs =0008** 代码选择器可见部分。我们使用段0x8.这也表明全局描述符表(0x8&4=0)和当前特权等级(CPL)为0x8&3=0
5656
2. **10000000** 段基地址。线性地址=逻辑地址+段基地址

content/12-xv6-lab/lab0-envs/02-docker.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ tags: ["xv6", "os"]
1010

1111
## Dockerfile
1212

13-
{{< highlight Dockerfile >}}
13+
```dockerfile
1414
FROM ubuntu:16.04
1515

1616
RUN apt-get -qq update
@@ -28,12 +28,12 @@ ADD ./jos jos
2828
WORKDIR jos
2929

3030
CMD ["/bin/bash"]
31-
{{< /highlight >}}
31+
```
3232

3333
## startup
3434

35-
{{< highlight bash >}}
35+
```bash
3636
joswd=$(pwd)
3737
echo ${joswd}
3838
docker run --rm -it -v ${joswd}/jos:/jos xv6
39-
{{< /highlight >}}
39+
```

content/12-xv6-lab/lab1-bootstrap/doc.md

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ tags: ["xv6", "os", "bootstrap"]
2727
在6.828课程中,我们将使用[QEMU](http://www.qemu.org/),QEMU可以配合[GDB](http://www.gnu.org/software/gdb/)一起使用,进行调试。
2828

2929
`lab`目录输入`make`,可以看到下面的输出
30-
{{< highlight text >}}
30+
```text
3131
+ as kern/entry.S
3232
+ cc kern/entrypgdir.c
3333
+ cc kern/init.c
@@ -45,15 +45,15 @@ ld: warning: section `.bss' type changed to PROGBITS
4545
+ ld boot/boot
4646
boot block is 390 bytes (max 510)
4747
+ mk obj/kern/kernel.img
48-
{{< /highlight >}}
48+
```
4949

5050
如果你有类似于"undefined reference to `__udivdi3`"这种错误,你可能没有32位gcc编译包,如果你运行在Ubuntu或Debian,尝试安装`gcc-multilib`包。使用我的Dockerfile,不会出现这个问题
5151

5252
现在,你准备运行QEMU,装载`obj/kern/kernel.img`文件,这个文件包含引导加载程序(obj/boot/boot)和内核(obj/kernel)
5353

5454
运行`make qemu`(有界面)或者`make qemu-nox`(无界面)。将会启动QEMU并且加载硬盘,成功进入系统。具体显示如下
5555

56-
{{< highlight text >}}
56+
```text
5757
6828 decimal is XXX octal!
5858
entering test_backtrace 5
5959
entering test_backtrace 4
@@ -70,13 +70,13 @@ leaving test_backtrace 5
7070
Welcome to the JOS kernel monitor!
7171
Type 'help' for a list of commands.
7272
K>
73-
{{< /highlight >}}
73+
```
7474

7575
### PC物理地址空间
7676

7777
一个计算机的物理内存地址通常是下面的结构
7878

79-
{{< highlight text >}}
79+
```text
8080
+------------------+ <- 0xFFFFFFFF (4GB)
8181
| 32-bit |
8282
| memory mapped |
@@ -106,7 +106,7 @@ K>
106106
| Low Memory |
107107
| |
108108
+------------------+ <- 0x00000000
109-
{{< /highlight >}}
109+
```
110110

111111
第一代PC是基于16位Intel 8088处理器,仅仅只有1MB的物理内存。因此早期PC的物理地址空间是从`0x00000000``0x000FFFFF`,而不是`0xFFFFFFFF`。其中640KB的区域被标记为只有早期计算机能够使用的RAM(random-access memory),实际上,非常早期的PC能够配置16KB,32KB,或者64KB大小的RAM
112112

@@ -124,23 +124,23 @@ Intel的80286和80386处理器最终打破了1MB的障碍,这两款处理器
124124
实验提供了一个`.gdbinit`文件,用来启动GDB的16位代码调试,并将其链接到正在监听的QEMU(如果没有起作用,你必须添加一个`add-auto-load-safe-path`在你的`.gdbinit`,确保`gdb`程序是按照上述的操作连到QEMU)
125125

126126
QEMU输出
127-
{{< highlight text >}}
127+
```text
128128
***
129129
*** Now run 'make gdb'.
130130
***
131131
qemu-system-i386 -nographic -drive file=obj/kern/kernel.img,index=0,media=disk,format=raw -serial mon:stdio -gdb tcp::25000 -D qemu.log -S
132-
{{< /highlight >}}
132+
```
133133

134134
GDB输出
135-
{{< highlight text >}}
135+
```text
136136
warning: A handler for the OS ABI "GNU/Linux" is not built into this configuration
137137
of GDB. Attempting to continue with the default i8086 settings.
138138
139139
The target architecture is assumed to be i8086
140140
[f000:fff0] 0xffff0: ljmp $0xf000,$0xe05b
141141
0x0000fff0 in ?? ()
142142
+ symbol-file obj/kern/kernel
143-
{{< /highlight >}}
143+
```
144144

145145
为什么QEMU会如此启动?这与Intel设计的8088处理器有关。因为PC里的BIOS是"硬连接"到物理地址的0x000F0000~0x000FFFFF的,这个设计保证了PC在开机或重启的时候,BIOS总是可以拿到控制权,这一点是非常重要的,因为开机的时候,机器的RAM没有处理器能够执行的其他软件。QEMU仿真器有自己的BIOS,位于处理器仿真的物理地址空间。当处理器重置的时候,仿真的处理器进入到实模式,设置`CS``0xF00``IP``0xFFF0`,以便执行从CS:IP段地址开始。段地址0xF000:0xFFF0是怎么转换成物理地址的呢?
146146

@@ -188,7 +188,7 @@ PC的软盘和硬盘被分成512字节的区域成为扇区(*sectors*)。一个
188188
当链接器计算程序的内存结构,它会为没有初始化的全局变量保留空间,这个部分被称为`.bss`,紧接者`.data`之后。C会把没有初始化的全局变量初始化成0。因此ELF二进制文件中的`.bss`没有内容。然而,链接器仅仅记录了`.bss`部分的地址和大小。加载器或程序本身必须把0分配给`.bss`部分
189189

190190
测试所有部分的名称,大小和链接地址,可以用指令`objdump -h obj/kern/kernel`
191-
{{< highlight text >}}
191+
```text
192192
Sections:
193193
Idx Name Size VMA LMA File off Algn
194194
0 .text 00001871 f0100000 00100000 00001000 2**4
@@ -205,14 +205,14 @@ Idx Name Size VMA LMA File off Algn
205205
CONTENTS, ALLOC, LOAD, DATA
206206
6 .comment 00000035 00000000 00000000 00013948 2**0
207207
CONTENTS, READONLY
208-
{{< /highlight >}}
208+
```
209209

210210
可以看到不仅仅是上面列的那些内容,但是其他的都不重要。其他的大部分都是保存调试信息的,实际运行过程中是不会加载到内存的
211211

212212
特别注意`.text`部分的"VMA"(或*link address*)和"LMA"(或*load address*),LMA是加载的地址,VMA是链接的地址。链接器以各种方式对链接地址进行二进制编码,例如当代码需要全局变量地址是,结果是如果从一个没有链接的地址执行,二进制通常不能工作。值得一提的是,可以生成不包含任何绝对地址的代码,这就是通常说的动态链接库,但是6.828不使用
213213

214214
通常,链接和加载地址是相同的,例如可以查看`.text`部分的引导扇区内容`objdump -h obj/boot/boot.out`。可以看到VMA和LMA都是0x7c00,说明引导扇区从这个地方开始加载程序
215-
{{< highlight text >}}
215+
```text
216216
Sections:
217217
Idx Name Size VMA LMA File off Algn
218218
0 .text 00000186 00007c00 00007c00 00000074 2**2
@@ -225,11 +225,11 @@ Idx Name Size VMA LMA File off Algn
225225
CONTENTS, READONLY, DEBUGGING
226226
4 .comment 00000035 00000000 00000000 00001253 2**0
227227
CONTENTS, READONLY
228-
{{< /highlight >}}
228+
```
229229

230230
引导扇区使用ELF程序头去决定怎么加载片段,程序头指定了要加载的内容和目标地址。你可以检查程序头,通过`objdump -x obj/kern/kernel`
231231

232-
{{< highlight text >}}
232+
```text
233233
obj/kern/kernel: file format elf32-i386
234234
obj/kern/kernel
235235
architecture: i386, flags 0x00000112:
@@ -260,7 +260,7 @@ Idx Name Size VMA LMA File off Algn
260260
CONTENTS, ALLOC, LOAD, DATA
261261
6 .comment 00000035 00000000 00000000 00013948 2**0
262262
CONTENTS, READONLY
263-
{{< /highlight >}}
263+
```
264264

265265
结果中的程序头部包含了`ELF`的相关信息,需要被加载进内存的用"LOAD"标记。其他信息,如`vaddr`是虚拟地址,`paddr`是物理地址,`memsz``filesz`是加载区域。在`boot/main.c`中的代码。
266266

@@ -273,12 +273,12 @@ BIOS把引导扇区加载到0x7c00的内存地址位置,因此这是引导扇
273273
现在回头来看看内核加载地址和链接地址。不像启动引导,这两个地址是不同的:内核告诉引导加载程序加载低地址(1MB)的内存,但是可能从一个高地址执行,将会在下一个部分深挖
274274

275275
除了段信息,ELF头部也有一个重要的部分,叫做`e_entry`,这个部分保留了程序入口的链接地址。可以通过`objdump -f obj/kern/kernel`查看入口地址
276-
{{< highlight text >}}
276+
```text
277277
obj/kern/kernel: file format elf32-i386
278278
architecture: i386, flags 0x00000112:
279279
EXEC_P, HAS_SYMS, D_PAGED
280280
start address 0x0010000c
281-
{{< /highlight >}}
281+
```
282282

283283
现在看来最小的`boot/main.c`中加载ELF,就是把内核从硬盘加载到内存,然后跳到内核入口
284284

0 commit comments

Comments
 (0)