CSAPP - Chapter6 存储器层次结构

6.1 存储技术 6.1.1 随机访问存储器 RAM SRAM DRAM ROM 6.1.2 磁盘存储 6.1.3 固态硬盘 大约十万次写会导致块损坏。 6.2 局部性 6.4 高速缓冲存储器 // todo: 添加截图 高速缓存确定一个请求是否命中,然后抽出被请求字的过程分为三步: 组选择 行匹配 字抽取 6.4.2 直接映射高速缓存 每组只有一行(E=1)。 // todo: 添加截图 6.4.3 组相连高速缓存 1<E<C/B 组选择 和直接映射高速缓存相同。 行匹配和字选择 每组的任何一行都可以包含任何映射到这个组的内存块。 所以高速缓存必须搜索组中的每一行,寻找一个有效行,其标记与地址中的标记相匹配。 行替换 行替换算法: LFU: Least frequently used. 替换过去某个时间窗口引用次数最少的一行。 LRU: Least recently used. 替换最后一次访问时间最久远的一行。 6.4.4 全相连高速缓存 //todo: 插图 E=CB,一个组包含所有行。 组选择 只有一个组,没有组索引。 行匹配和字选择 构建一个又大又快的相连高速缓存很困难,而且很昂贵。因此全相连高速缓存只适合做小的高速缓存,例如虚拟内存中的 TLB。 6.4.5 有关写的问题 写命中 假设我们要写一个已经缓存了的字 w(写命中)。 首先都会先更新高速缓存中的字 w,接着更新低一级的内存中的数据,有两种方式: write-through 直写。立即将 w 的高速缓存块写回到低一层中。 wirte-back 写回。尽可能地推迟更新,只有当替换算法要驱逐这个更新过的块时,才写到低一层去。 写回可以显著减少总线流量,但增加了复杂性,需要额外维护一个 dirty bit,表示这个高速缓存快块是否修改过。...

2024-07-28 · 1 min

CSAPP - Chapter5 优化程序性能

5.1 优化编译器的能力和局限性 gcc 优化等级: -O0:这是默认的优化等级,基本上不进行任何优化,以便于调试。源代码会被尽可能地转化为目标代码,而不会对程序的执行速度进行优化。 -O1:这是一个适度的优化等级,它会在编译时执行一些简单的优化,如常量折叠、死代码删除、循环展开等,但不会影响编译时间太多。这个等级的优化通常不会显著改变程序的行为。 -O2:这是最常见的优化等级,它会执行更多的优化,包括函数内联、循环优化、寄存器分配等,可能会稍微增加编译时间,但是通常可以产生更快的可执行文件。 -O3:这是最高级别的优化,它包含了-O2 中的所有优化,并且会执行更激进的优化策略,如更多的内联、循环展开等。这可能会显著增加编译时间,但同时也可能产生执行效率最高的代码。 -Os:这个优化等级专注于减少输出文件的大小,同时仍然保持一定的运行时性能。它会使用一些特定的技巧来减小代码和数据的大小,适合用于嵌入式系统或资源有限的环境。 -Og:这个优化等级主要用于调试,它会生成更多的调试信息,同时尽量保持源代码和目标代码的一致性,以便于调试。 -Ofast:这是为了追求极致性能的优化等级,它会启用所有可用的优化,并且可能会违反 C/C++语言标准的一些规则,比如浮点运算的精度可能会有所损失。 两种指针可能指向同一个内存位置的情况称为内存别名使用。 比如 void twiddle1(long *xp, long *yp) { *xp += *yp; *xp += *yp; } void twiddle2(long *xp, long *yp) { *xp = 2* *yp; } 在xp和yp指针不指向同一地址时,twiddle1可以被优化成twiddle2,但如果xp == yp,那结果就不一样了,twiddle1该地址的值会变成 4 倍,而twiddle2只是两倍。所以编译器对这种情况不能进行优化。 提供一个 combine1 函数,看看我们能如何来优化它。 // for add #define IDENT 0 #define OP + // for multiply #define INENT 1 #define OP * void combine1(vec_ptr v, data_t *dest) { long i; *dest = IDENT; for (i = 0; i < vec_length(v); i++) { data_t val; get_vec_element(v, i, &val); *dest = *dest OP val; } } int get_vec_element(vec_ptr v, long index, data_t *dest) { if (index < 0 || index >= v->Len) return 0; *dest = v->data[index]; return 1; } long vec_length(vec_ptr v) { return v->len; } 5....

2024-07-21 · 2 min

CSAPP - Attack Lab

文件说明 ctarget: An executable program vulnerable to code-injection(CI) attacks. rtarget: An executable program vulnerable to return-oriented-programming(ROP) attacks. cookie.txt: An 8-digit hex code that you will use as a unique identifier in your attack farm.c: 用来生成 ROP 攻击的代码。 hex2raw: 生成攻击字符串的工具。 输入ctarget -h查看帮助信息: Usage: [-hq] ./ctarget -i <infile> -h Print help information -q Don't submit result to server -i <infile> Input file 我们在本地跑的话必须加上-q选项,否则会提示Running on an illegal host错误。 工具使用 hex2raw hex2raw 可以将文本中保存的 ascii 码值转化成字符串。注意每个 ascii 需要以空格分开,可以加注释(注释/* */前后需要空格)。...

2024-07-05 · 10 min

CSAPP - Data Lab

Build ./dlc bits.c: 用来检查是否符合coding guidelines. ./dlc -e bits.c: 显示每个函数用了多少个操作符。 make btest: 编译btest。 make clean Rules Each "Expr" is an expression using ONLY the following: 1. Integer constants 0 through 255 (0xFF), inclusive. You are not allowed to use big constants such as 0xffffffff. 2. Function arguments and local variables (no global variables). 3. Unary integer operations ! ~ 4. Binary integer operations & ^ | + << >> You are expressly forbidden to: 1....

2024-06-25 · 1 min

Keil相关内存设置

内存设置 off-chip和on-chip本质上没有区别,只是地址会不同。 假如ic都是on-chip sram,要分成三块的话,把一块写到off-chip就可以。 NoInit不勾选的话,每次进main函数前会对该memory进行清0的操作。 前面default是默认的变量保存地址。 修改变量地址 可以直接在keil左侧对文件右击,选择第一个option for file,对该文件中的变量地址进行修改。 Code/Const会保存到default的ROM中。 Zero initialized Data是bss段数据(未初始化的和初始化为0的全局变量,函数中的static变量)。 Other data是data段数据(初始化为非0的全局变量,函数中的static变量)。 对启动文件中的zero initialized data修改位置,将会更改栈和堆的地址。 还可以直接在code中修改某个变量的地址: sdcp_keypair g_tFWKey __attribute__((section(".ARM.__at_0x20000000")));

2024-06-21 · 1 min

CSAPP - Bomb Lab

Setup 新建solution.txt保存答案, 运行./bomb solution.txt进行测试。 gdb bomb (gdb) r solution.txt 注意如果solution.txt 每行的结尾需要是LF结尾,否则无法正确解析。 objdump -t bomb > bomb_symbol_table.txt: 生成符号表。 objdump -d bomb > bomb.txt: 生成反汇编文件。 Answer Bomb1 首先根据bomb.txt找到bomb的执行入口main函数。 400e32: e8 67 06 00 00 call 40149e <read_line> # 读取输入的一行 400e37: 48 89 c7 mov %rax,%rdi # 把读取的字符串地址传入%rdi 400e3a: e8 a1 00 00 00 call 400ee0 <phase_1> # 调用phase_1,传入的第一个参数为%rdi 400e3f: e8 80 07 00 00 call 4015c4 <phase_defused> 400e44: bf a8 23 40 00 mov $0x4023a8,%edi 400e49: e8 c2 fc ff ff call 400b10 <puts@plt> 400e4e: e8 4b 06 00 00 call 40149e <read_line> 400e53: 48 89 c7 mov %rax,%rdi 400e56: e8 a1 00 00 00 call 400efc <phase_2> 400e5b: e8 64 07 00 00 call 4015c4 <phase_defused> 400e60: bf ed 22 40 00 mov $0x4022ed,%edi 400e65: e8 a6 fc ff ff call 400b10 <puts@plt> //....

2024-06-13 · 11 min

CSAPP - Chapter3 程序的机器级表示

3.3 数据格式 Intel用术语字来表示16位数据类型。 32位:双字。 64位:四字。 3.4 访问信息 %rbp是帧指针。 生成1字节和2字节数字的指令会保持剩下的字节不变; 生成4字节数字的指令会把高位的4个字节置为0。 3.4.1 操作数指示符 3.4.2 数据传送指令 MOV S, D: S->D 传送指令和的两个操作数不能都指向内存地址。 movabsq: 常规的movq指令只能以表示为32位补码数字的立即数作为源操作数。然后把这个值符号扩展得到64位的值,放到目的位置。 movabsq指令能够以任意64位立即数作为源操作数,并且只能以寄存器作为目的。 MOVZ S, R: 零扩展(S)->R MOVS S, R: 符号扩展(S)->R 这两个指令目的只能是寄存器。 cltq: 符号扩展(%eax)->%rax, 把%eax符号扩展到%rax。 3.4.4 压入和弹出栈数据 练习题 3.2 内存引用总是以4字节寄存器给出,比如%rax。 练习题 3.3 movl %eax, %rdx: 目的寄存器%rdx长度不匹配,应该为%edx。 3.5算术和逻辑操作 图3-10: 3.5.1 加载有效地址 如果%rdx保存的值为x leaq 7(%rdx, %rdx, 4), %rax: 将%rax寄存器的值设为5x+7。 指令形式是从内存读数据到寄存器,但实际上根本没有引用内存。 3.5.3 移位操作 移位量可以是一个立即数,或者放在单字节寄存器%cl中。(只允许以这个特定的寄存器) 3.5.5 特殊的算术操作 //TODO: 3.6 控制 3.6.1 条件码 CF: 进位标志。 ZF: 零标志。...

2024-06-07 · 3 min

xv6_lab3 trap

Q1 RISC-V assembly C 代码: int g(int x) { return x+3; } int f(int x) { return g(x); } void main(void) { printf("%d %d\n", f(8)+1, 13); exit(0); } 生成的汇编代码: 000000000000001c <main>: void main(void) { 1c: 1141 addi sp,sp,-16 // 分配栈空间 1e: e406 sd ra,8(sp) // 保存main的返回地址,因为接下来要调用printf 20: e022 sd s0,0(sp) // 保存前一个函数的frame pointer 22: 0800 addi s0,sp,16 // 现在frame pointer要增加16Bytes printf("%d %d\n", f(8)+1, 13); 24: 4635 li a2,13 26: 45b1 li a1,12 28: 00000517 auipc a0,0x0 2c: 7a050513 addi a0,a0,1952 # 7c8 <malloc+0xe8> // "%d %d\n"字符串地址 30: 00000097 auipc ra,0x0 // ra=pc=0x30 34: 5f8080e7 jalr 1528(ra) # 628 <printf> // 0x30 + 0x5f8 = 0x628 exit(0); 38: 4501 li a0,0 // exit的参数,传入0 3a: 00000097 auipc ra,0x0 3e: 274080e7 jalr 628(ra) # 2ae <exit> 1....

2024-06-04 · 2 min

CSAPP - Chapter2 信息的表示和处理

2.1.1 十六进制表示法 2的整数幂转化为16进制: 多少次方就有多少个零。 \(2048 = 2^{11}\) \(n = 11 = 3 +4*2\) 因此十六进制表示为0x800。 2.1.2 字数据大小 计算机字长等于指针数据的长度,32/64。 2.1.3 寻址和字节顺序 typedef unsigned char *byte_pointer; void show_bytes(byte_pointer start, size_t len) { size_t i; for (int i = 0; i < len; i++) printf("%.2x\n", start[i]); } int val = 0x87654321 byte_pointer valp = (byte_pointer)&val; show_bytes(valp, 1); // 结果是0x21, 小端法低地址保存的是数据低有效位 const char *s = "12345"; show_bytes((byte_pointer)s, strlen(s)); // 结果是31 32 33 34 35。没有字符串结尾的00,因为strlen不统计结束符。 // 注意字符串会以顺序排列,和字节序无关。 2....

2024-05-25 · 1 min

Zephyr -- Power Management

System PM CONFIG_PM开关。用来控制整个SoC的状态。 Device tree zephyr,power-state.yaml介绍了zephyr power state的device tree binding。 一个设备树的例子: power-states { idle: idle { compatible = "zephyr,power-state"; power-state-name = "runtime-idle"; }; stop: stop { compatible = "zephyr,power-state"; power-state-name = "suspend-to-idle"; // pm状态,见yaml substate-id = <0>; // 如果有两个相同的power-state-name,需要用substate-id来区分 min-residency-us = <1000>; // 最少在该状态停留的时间 exit-latency-us = <2>; // 离开该状态最worse的时间 }; pstop1: pstop1 { compatible = "zephyr,power-state"; power-state-name = "suspend-to-idle"; substate-id = <1>; min-residency-us = <1000>; exit-latency-us = <2>; }; }; PM policy 有两种PM policy:...

2024-05-16 · 4 min