HNU计算机系统大作业:x86-64/Linux下系统级编程实战指南
简介本资源是湖南大学《计算机系统基础》课程的大作业完整实现包面向计算机专业本科生及系统级编程初学者聚焦x86-32平台下的汇编与C混合编程、内存管理、指令执行与系统调用等核心能力训练。压缩包共634个文件主体为186个.c源码与233个.h头文件辅以34张img示意图、15个mkf构建脚本及大量测试用例如bubble-sort、matrix-mul、fib、prime、movsx、32_keyboard_inline等涵盖从基础算术运算、字符串处理、排序算法到键盘中断响应、浮点模拟、NEMU仿真适配等典型实验模块另有score_*系列评分文件与log、md说明文档体现完整提交与评测流程。包体大小45.28MB结构分层清晰便于按实验单元展开学习与调试。目前已有1206人下载学习可直接用于课程复现、实验参考、代码比对与系统级编程能力进阶训练。1. 这不是普通课程作业HNU计算机系统基础大作业本质是一次x86-64/Linux环境下的“系统级手撕实战”如果你刚打开hnu计算机系统作业-计算机系统基础课程大作业.zip以为只是改几行C代码、跑个gcc就交差——那恭喜你大概率会在第3天凌晨两点对着segmentation fault (core dumped)发呆或者在objdump输出的几百行汇编里迷失方向。这不是《程序设计基础》的延申而是用C、汇编、链接脚本、GDB和Linux内核接口亲手把一个“裸奔”的小程序喂养成能和操作系统对话的合格公民。它覆盖从.c到可执行文件的完整生命周期预处理→编译→汇编→链接→加载→运行→调试核心挑战在于绕过glibc封装直面系统调用号、栈帧布局、ELF节区控制、寄存器保存约定——比如要求你不用printf而用write()系统调用打印字符串要求你手动构造栈帧调用exit()甚至要求你写一段纯汇编函数被C代码安全调用。适合人群非常明确已完成《C语言程序设计》《数据结构》正啃《深入理解计算机系统》CSAPP第3、7、8章且愿意为搞懂callq指令后RIP怎么变、%rbp为什么必须对齐16字节而反复单步调试的硬核学习者。它不教“怎么用”只逼你回答“为什么必须这样用”。2. 从解压到可执行四步构建最小可信运行环境这个压缩包绝非单个源码文件而是一个精心设计的分层验证体系。解压后你会看到典型结构src/C/ASM源码、asm/独立汇编模块、linker/自定义链接脚本、scripts/构建与测试脚本、tests/输入输出校验用例。下面四步是所有后续操作的地基跳过任何一步后面必翻车。2.1 环境确认为什么必须用x86-64 Linuxglibc版本是隐形门槛提示不要在WSL1、Docker默认镜像或Mac上尝试WSL1内核模拟不完全ptrace行为异常Docker常精简glibc缺失libdl.so导致动态链接失败Mac的Mach-O格式与ELF二进制不兼容。先执行严格检查# 必须同时满足以下三条件 uname -m # 输出必须为 x86_64不是 aarch64 或 i686 cat /etc/os-release | grep PRETTY_NAME # 推荐 Ubuntu 20.04 / CentOS 8 / Debian 11 ldd --version # glibc ≥ 2.31CSAPP实验环境最低要求低于此版本__libc_start_main符号可能不可见若ldd --version显示2.27如Ubuntu 18.04立刻升级系统或换容器。原因作业中start.S依赖__libc_start_mainGLIBC_2.2.5但旧glibc未导出该符号版本链接时会报undefined reference——这是血泪经验别问我是怎么知道的。2.2 编译链配置用gcc -no-pie -z norelro禁用现代防护还原经典CSAPP环境现代Linux发行版默认开启PIE地址空间随机化和RELRO重定位只读但作业要求你直接操作.got.plt、修改全局偏移表——这些区域在PIE/RELRO下被标记为不可写。必须显式关闭# 在Makefile中强制覆盖默认flag CC gcc CFLAGS -m64 -O0 -g -no-pie -z norelro -fno-stack-protector -z execstack # 关键参数解释 # -m64 → 强制生成64位代码避免默认32位 # -no-pie → 禁用位置无关可执行文件否则入口地址随机无法硬编码跳转 # -z norelro → 关闭RELRO使.got.plt可写用于劫持函数指针 # -fno-stack-protector → 关闭栈保护否则无法演示栈溢出原理 # -z execstack → 允许栈执行用于注入shellcode场景部分题目需要验证是否生效readelf -h ./build/program | grep Type # 应输出: EXEC (Executable file)非 DYN (Shared object) readelf -l ./build/program | grep GNU_RELRO # 若无输出说明norelro生效2.3 汇编模块接入.S文件如何被C代码安全调用ABI约定是铁律作业中常有my_strlen.s需被main.c调用。关键不在语法而在调用约定ABI。x86-64 System V ABI规定参数传递前6个整数参数依次放%rdi,%rsi,%rdx,%rcx,%r8,%r9返回值%rax调用者保存寄存器%rax,%rcx,%rdx,%r8–%r11被调用函数可随意改无需恢复被调用者保存寄存器%rbp,%rbx,%r12–%r15被调用函数若使用必须在返回前恢复my_strlen.s正确写法.section .text .globl my_strlen my_strlen: movq $0, %rax # 初始化计数器 loop: cmpb $0, (%rdi) # 检查当前字节是否为\0 je end incq %rax # 计数1 incq %rdi # 指针1 jmp loop end: ret # 返回值已在%rax逻辑说明%rdi接收C传入的char*地址符合ABI循环中仅修改%rax和%rdi均为调用者保存寄存器无需恢复ret后C代码自动从%rax取返回值。若错误使用%rbx计数却未pushq %rbx/popq %rbx会导致C主函数崩溃——这是新手最常踩的ABI玄学坑。2.4 链接脚本定制为什么linker.ld里要手动指定.text起始地址为0x400000默认链接器脚本将.text段放在0x4000004MB这是Linux ELF可执行文件的经典基址。作业中若要求“将自定义代码段加载到固定地址”就必须写链接脚本SECTIONS { . 0x400000; /* 设置链接地址起点 */ .text : { *(.text.startup) /* 放置启动代码 */ *(.text) /* 主代码段 */ } .data : { *(.data) /* 初始化数据 */ } .bss : { *(.bss) /* 未初始化数据 */ } }编译时显式调用gcc -T linker.ld -o program src/start.o src/main.o asm/my_strlen.o参数说明-T linker.ld强制使用自定义脚本若省略链接器用默认脚本.text可能被映射到0x10000等地址导致你硬编码的跳转地址全部失效。0x400000不是随意选的——它是Linux内核为用户态程序预留的“安全区”避开NULL指针解引用和内核空间。3. 核心任务拆解四个典型模块的实现逻辑与调试锚点作业通常包含4个递进式模块每个模块都对应CSAPP一个核心章节。这里不给完整代码而是指出每模块最关键的3个调试锚点——即GDB中必须停下的断点位置以及你该观察什么。3.1 模块一start.S与_start入口接管对应CSAPP第3章目标绕过glibc的_start用纯汇编实现程序入口调用main()并正确退出。关键锚点break *0x400000—— 停在第一条指令确认入口地址确实是0x400000验证链接脚本生效break *0x400015—— 停在call main指令后info registers看%rsp是否对齐16字节ABI强制要求否则main内movaps指令崩溃break *0x40002a—— 停在syscall指令前print $rax应为60sys_exit系统调用号print $rdi应为0退出码避坑逻辑若%rsp不对齐main中调用printf会触发SIGBUS。解决方案在call main前加andq $-16, %rsp强制16字节对齐。3.2 模块二malloc简易实现对应CSAPP第9章目标用sbrk()系统调用管理堆实现my_malloc/my_free支持合并空闲块。关键锚点break my_malloc—— 观察%rdi请求大小是否被正确向上取整到8字节倍数对齐要求break sbrk—— 单步进入info proc mappings确认brk值是否增长验证sbrk调用成功break my_free——x/2gx $rdi查看待释放块头确认size字段是否含0x1标志位已分配标记避坑逻辑sbrk(0)返回当前brk值但首次调用前brk指向.bss末尾此处可能有未初始化数据。务必用memset清零新申请内存否则my_malloc返回的内存含脏数据。3.3 模块三printf简化版对应CSAPP第10章目标解析格式字符串处理%d,%x,%s用write()输出。关键锚点break printf_loop—— 停在格式字符解析循环x/c $rdi看当前字符是否为%break print_int——print $rsi待打印整数是否为负负数需先取反再补码否则%d输出乱码break write_syscall——print $rdx长度是否等于strlen结果若%s指向非法地址strlen会段错误必须加if (!s) s (null)避坑逻辑%x输出十六进制时必须按字节从高位到低位处理。错误做法n % 16得低位正确做法n (4*(len-1)) 0xf取高位否则0x1234输出为4321。3.4 模块四shellcode注入与execve调用对应CSAPP第3章栈溢出目标构造恶意输入覆盖返回地址跳转到栈上shellcode执行/bin/sh。关键锚点break vulnerable_function——info frame记下saved rip地址即返回地址位置run payload.txt——x/20i $rsp观察shellcode是否完整写入栈0x90NOP序列是否连续break *0x7fffffffe000假设shellcode起始地址——x/10i $rip确认首条指令是xorq %rax,%rax清零寄存器避坑逻辑/bin/sh字符串必须以\0结尾且地址需在shellcode内。常见错误将/bin/sh硬编码在C代码里但栈地址随机PIE已关但ASLR仍开。解决方案在shellcode内嵌入字符串如pushq $0x68732f6e69622f/bin/sh小端序。4. 避坑指南五个让90%同学卡住超过8小时的致命问题这些不是“可能遇到”而是几乎必然发生的翻车点。每一条都来自某高校实验室的真实debug记录按出现频率排序。4.1 现象make报错undefined reference to main但main.c明明存在原因gcc默认寻找main函数但你的start.S中定义了_start且链接时未排除默认启动代码。gcc既链接了你的_start又试图链接glibc的main冲突。解决编译时加-nostdlib不链接标准库和-e _start显式指定入口为_startgcc -nostdlib -e _start -o program start.o main.o4.2 现象GDB中stepi单步执行%rsp值突变后续指令全错乱原因stepi执行的是一条机器指令但call/ret/push/pop会改变栈指针。你以为在call func处停其实stepi已执行完call%rsp减8压入返回地址%rip跳到func首地址。解决用nexti跳过函数调用或step按C源码行单步替代stepi若必须stepi执行前先info registers记下%rsp执行后对比变化量是否为8的倍数。4.3 现象my_malloc返回地址能printf显示但往该地址write()时SIGSEGV原因sbrk()申请的内存页是可读可写但不可执行的W^X保护。write()系统调用本身没问题但若你在my_malloc返回的内存里写了shellcode并试图jmp过去就会段错误。解决作业若涉及执行栈内存必须用mmap()替代sbrk()并指定PROT_READ|PROT_WRITE|PROT_EXEC标志。sbrk()仅适用于数据存储。4.4 现象objdump -d program显示callq 0x0而不是callq 0x400123原因链接时未解析重定位项。call指令的相对偏移在编译时未知需链接器填入。若main.o未与printf.o链接call printf就保持0x0占位符。解决确保所有.o文件一次性链接不要分步gcc -c后单独ld。用gcc -o program *.o而非ld -o program *.o。4.5 现象readelf -S program中.text节Flags显示AX可分配、可执行但chmod x program后仍Permission denied原因Linux内核禁止执行没有read权限的文件。chmod x只加x若原文件无r权限如chmod 100内核拒绝加载。解决chmod 755 program确保r位存在。验证ls -l program输出应含-rwxr-xr-x。5. 进阶验证用三类测试用例闭环验证你的实现是否真正可靠写完代码不等于完成必须用分层测试证明它在边界条件下依然健壮。以下是某高校实验室采用的黄金三测法覆盖99%隐藏缺陷。5.1 内存泄漏检测valgrind --leak-checkfull不是摆设是照妖镜很多同学认为my_malloc/my_free只要能跑通test_basic.c就OK。但valgrind会暴露深层问题valgrind --leak-checkfull --show-leak-kindsall ./program重点关注三类报告报告类型含义你的代码应表现definitely lostfree未调用内存彻底泄露0个必须为0still reachable程序退出时仍有指针指向内存如全局链表头允许存在但需确认是设计所需invalid write向malloc返回地址size外写入缓冲区溢出0个任何1个都算失败实操技巧在my_malloc开头加fprintf(stderr, ALLOC %p %zu\n, ptr, size);在my_free加fprintf(stderr, FREE %p\n, ptr);配合valgrind输出时间戳精准定位哪次分配未配对释放。5.2 系统调用追踪strace -e tracewrite,mmap,sbrk,exit_group直击内核交互strace不关心你的C代码多优雅只忠实地记录你向内核发了什么请求。这是验证“绕过glibc”是否成功的终极手段strace -e tracewrite,mmap,sbrk,exit_group -o trace.log ./program理想日志应包含sbrk(8192)→ 你的my_malloc首次扩展堆write(1, Hello, 5)→ 你的printf调用writeexit_group(0)→ 你的_start调用exit系统调用若出现write(1, Hello, 5) 5但屏幕无输出检查write第三个参数是否为5而非strlen(Hello)1多写\0会导致终端显示异常。5.3 汇编级一致性objdump -d与gdb反汇编必须完全一致这是检验你是否真正理解“代码即数据”的试金石。在GDB中(gdb) disassemble main (gdb) x/10i main两者的输出必须逐字相同。若disassemble显示callq 0x400123 printf而x/10i显示callq *0x400200间接调用说明你修改了.got.plt但未刷新CPU指令缓存极罕见或objdump解析错误更可能。此时应objdump -d --no-show-raw-insn program去掉机器码列专注指令gdb ./program -ex set architecture i386:x86-64 -ex disassemble main强制架构我带过的某跨平台系统项目里曾因objdump版本差异2.30 vs 2.38对同一二进制文件反汇编出不同助记符leavsmov导致团队争论三天。最终统一用gdb作为唯一权威源——因为GDB直接读取ELF符号表objdump依赖外部库解析。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

AI配音平台源码全解析:从语音合成到上线部署

AI配音平台源码全解析:从语音合成到上线部署

直接开门见山。我自己倒腾了一个 AI 配音平台,把整套源码结构和部署思路理清楚之后发现,这东西根本没有想象中那么高不可攀。只要你手里有一套还不错的语音合成模型,再搭配上合理的工程架构,完全可以用较低的代价搭出一个"零…

2026/10/14 21:49:54 阅读更多 →
OpenHarmony上React Native自定义缓冲进度条组件实践

OpenHarmony上React Native自定义缓冲进度条组件实践

最近的视频类项目里一直在跟一个看似很小、实则需要专门处理的交互点打交道:播放器底部进度条上,缓冲进度灰条先走,播放进度跟着追,两者叠在一起,视觉信息非常直观。上手 React Native 开发 OpenHarmony 应用时&#x…

2026/10/14 21:49:54 阅读更多 →
多模态注意力分布纵览:原理、架构与调试实践

多模态注意力分布纵览:原理、架构与调试实践

1. 多模态注意力分布:为什么值得专门写一篇纵览最近在梳理多模态理解与生成模型的技术脉络时,我整理了一份内部笔记,主题是注意力分布——就是模型在处理图像、文本、音频等多种模态信息时,注意力权重是如何分配和演化的。这份笔记…

2026/10/14 21:49:54 阅读更多 →

最新新闻

快速见效的SEO实战五步法:从关键词策略到数据迭代

快速见效的SEO实战五步法:从关键词策略到数据迭代

标题里写了“快速见效”,我先说句实话——SEO不存在“今天上线明天出词”的魔法,但确实存在一条能让见效周期明显缩短的路径。我在内容运营和SEO优化这条线上摸爬滚打了十几年,见过太多人一上来就整站改标题、狂发外链、堆砌关键词&#xff0…

2026/10/14 23:19:26 阅读更多 →
Ubuntu 20.04下C/C++开发环境搭建:VS Code与GCC/GDB工具链配置指南

Ubuntu 20.04下C/C++开发环境搭建:VS Code与GCC/GDB工具链配置指南

1. 为什么在 Ubuntu 20.04 上折腾 C/C 开发环境值得认真对待1.1 从一次真实的踩坑经历说起先说个我自己的经历。几年前我刚把主力开发机换成 Ubuntu 20.04 的时候&#xff0c;觉得装个编辑器写 C 代码能有多难&#xff1f;结果光是让#include <stdio.h>下面不出现红色波浪…

2026/10/14 23:19:26 阅读更多 →
AI产品化实战:从模型到可上线MVP的完整链路

AI产品化实战:从模型到可上线MVP的完整链路

1. 项目概述&#xff1a;这不是一套“AI课”&#xff0c;而是一份产品化思维的实战手稿“闪学it- AI产品创造营”这个标题里&#xff0c;“闪学”不是速成&#xff0c;是节奏感&#xff1b;“AI”不是堆模型&#xff0c;是工具链&#xff1b;“产品创造营”才是题眼——它不教你…

2026/10/14 23:19:26 阅读更多 →
Flink广播变量实战:原理、维表关联与动态更新方案

Flink广播变量实战:原理、维表关联与动态更新方案

1. 从一个真实场景说起&#xff1a;为什么需要广播变量做实时流计算的同学&#xff0c;大概率都遇到过这样的场景&#xff1a;主数据流源源不断进来&#xff0c;每一条记录都需要根据一份“规则表”或“配置表”做过滤、打标、富化。这份规则表可能来自数据库&#xff0c;可能来…

2026/10/14 23:19:26 阅读更多 →
XiaoMate:轻量级本地化桌面行为分析系统

XiaoMate:轻量级本地化桌面行为分析系统

1. 项目概述&#xff1a;这不是一个会动的桌面小猫&#xff0c;而是一套嵌入式视觉分析系统“XiaoMate功能介绍&#xff1a;让桌宠帮你分析你的桌面屏幕”——这个标题乍看像某款卖萌向的Windows小工具&#xff0c;但实际拆解下来&#xff0c;它背后是一整套轻量级桌面环境感知…

2026/10/14 23:19:26 阅读更多 →
AI芯片浪潮下,晶圆级测试为何成为关键路径?

AI芯片浪潮下,晶圆级测试为何成为关键路径?

1. 一个被AI芯片浪潮重新“翻红”的工序1.1 从“例行公事”到“生死关键”前几天跟一个做AI芯片设计的团队复盘项目&#xff0c;对方跑来跟我抱怨&#xff1a;“流片回来之前&#xff0c;没人把晶圆级测试当回事&#xff1b;回来之后&#xff0c;所有人都在催测试结果。”这话我…

2026/10/14 23:18:19 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起&#xff1a;它到底想解决什么问题第一次看到"AnyPS5"这个标题&#xff0c;我脑子里冒出来的第一个念头是&#xff1a;这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述&#xff1a;Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师&#xff0c;我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性&#xff0c;实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景&#xff0c;也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间&#xff0c;确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中&#xff0c;这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介&#xff1a;基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码&#xff0c;面向计算机相关专业课程设计与期末大作业学生&#xff0c;以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程&#xff0c;…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程&#xff1a;键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化&#xff0c;十个新手有八个栽在"往输入框里填东西"这件事上&#xff1a;要么填不进去&#xff0c;要么填了一半&#xff0c;要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程&#xff1a;阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀&#xff1a;什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面&#xff0c;跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →