简介:本资源是天津大学《计算机系统基础》课程配套的完整上机实验资料包,面向计算机专业本科生及系统编程初学者,聚焦底层原理实践与安全编程能力培养。内容覆盖位操作、整数与浮点数表示、缓冲区溢出分析(拆弹专家)、代码注入攻击防御、高速缓存优化五大核心实验模块,直击计算机组成原理与系统安全的关键难点。压缩包共35个文件,含14份PDF实验指导与报告、6个C语言源码(含bomb、ctarget等可执行靶场程序)、4份Word实验文档、2个汇编文件及PNG图示等,类型丰富且高度对应实验环节;整体大小为112.48MB,结构清晰,便于分模块学习与调试复现。已有921人下载学习,提供从实验环境搭建、漏洞触发分析到缓存性能调优的全流程支撑材料,特别适合夯实系统级编程基础、备战相关课程考核或CTF底层挑战。
1. 天津大学计算机系统基础实验:别被“简单上机”骗了,环境配错直接卡死在第一条汇编指令
很多同学点开天津大学计算机系统基础实验指导书,看到“实验一:熟悉Linux环境与GCC工具链”,心里一松——不就是装个虚拟机、敲几行gcc吗?结果真动手时,./configure报错说找不到m4,make卡在as: unrecognized option '--64',甚至用objdump -d hello.o看反汇编,输出全是问号和乱码……这不是你手生,是这套实验对底层环境的咬合度极苛刻:它不跑在“能用”的Linux上,而必须跑在“原教旨级匹配”的x86_64 GNU Binutils + GCC + Glibc组合里。实验文档里没明说,但所有.s汇编模板、.o目标文件校验、gdb单步跟踪断点行为,都隐式依赖于特定版本的gas(GNU Assembler)语法兼容性与ELF节区布局。我帮某高校实验室迁移过三届实验环境,最常翻车的不是代码写错,而是学生用Ubuntu 22.04默认的binutils 2.38去跑要求binutils 2.34的实验脚本——链接器悄悄改了.plt节对齐方式,导致call printf跳转地址偏移2字节,gdb里单步到一半就段错误。如果你正卡在“实验一编译不过”“实验二gdb看不到寄存器值”“实验三make check全fail”,这篇就是为你写的血泪安装笔记:从零开始,只用官方源+手动编译,搭一套经得起make test锤炼的天津大学计算机系统基础实验环境。
2. 准备实验基座:选对Linux发行版与内核版本是第一道生死线
天津大学计算机系统基础实验不是通用编程课,它本质是一门“与机器对话”的硬核实践课。所有实验设计(尤其是实验二至实验五的栈帧分析、函数调用约定、内存布局观察)都建立在x86_64 ABI规范与GNU工具链特定实现细节之上。这意味着:发行版不能随便选,内核不能盲目升,包管理器不能无脑apt install。我们得回到那个“每个字节都可控”的年代——用最小化、可追溯、可复现的基座。
2.1 为什么必须用Debian 11(bullseye)而非Ubuntu或新版Debian?
实验原始环境由天津大学某实验室在2020年搭建并固化,其构建日志显示全部工具链均基于Debian 11的软件源快照(2021年Q3)。关键证据有三:
- 实验三中
stack_protector_test.c的__stack_chk_fail符号解析依赖于glibc 2.31-13+deb11u8的特定符号版本定义; - 实验四
malloc_trace.c使用malloc_hook机制,该机制在glibc 2.34+中已被标记为deprecated,而Debian 12默认glibc 2.36已彻底移除; - 所有
.ld链接脚本中硬编码的/usr/lib/x86_64-linux-gnu/Scrt1.o路径,在Ubuntu系中实际位于/usr/lib/x86_64-linux-gnu/Scrt1.o(多一层x86_64-linux-gnu),导致ld -T链接失败。
提示:不要试图用Docker模拟——实验要求
/proc/self/maps实时可见、perf事件可捕获、/sys/kernel/debug可挂载,这些在默认Docker容器中均被cgroup或seccomp策略禁用。必须用真实虚拟机或物理机。
2.2 虚拟机配置实操:4GB内存+2核CPU+20GB磁盘的硬性下限
我们用VirtualBox 7.0(或VMware Workstation 17)创建一台纯净虚拟机,严格按以下参数配置:
| 项目 | 推荐值 | 为什么必须这样 |
|---|---|---|
| 操作系统类型 | Debian (64-bit) | VirtualBox对Debian优化最好,避免vboxguest驱动兼容问题 |
| 内存 | 4096 MB | 实验五valgrind --tool=memcheck运行big_array.c需至少3.2GB可用内存,低于此值会触发valgrind: out of memory |
| 处理器数量 | 2 CPU | make -j2并行编译是实验Makefile默认设置,单核会导致make check超时失败 |
| 硬盘 | VDI格式,动态分配,20GB | 实验所有源码+编译产物+调试符号总计约12.7GB,预留7GB给/usr/src/linux-headers-*(实验四需编译内核模块) |
安装过程选择“Debian 11.9 netinst”镜像( https://cdimage.debian.org/cdimage/archive/11.9.0/amd64/iso-cd/debian-11.9.0-amd64-netinst.iso ),安装时务必勾选“SSH server”和“Standard system utilities”,其余全部取消。安装完成后首次启动,执行:
# 更新源为国内镜像(以清华源为例) sudo sed -i 's|http://deb.debian.org|https://mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list sudo apt update && sudo apt full-upgrade -y # 安装基础编译工具(但先不装gcc/g++!留给我们手动编译) sudo apt install -y build-essential zlib1g-dev libncurses5-dev flex bison libssl-dev2.3 内核版本锁定:5.10.0-29-amd64是唯一安全选项
实验四涉及/proc/kallsyms符号读取与kprobe简易模块,其内核API在5.10.x系列稳定,但在5.15+中kallsyms_lookup_name被移除。Debian 11默认内核为5.10.0-29-amd64(2023年12月最后更新版),必须锁定此版本,禁止任何apt upgrade自动升级内核:
# 查看当前内核 uname -r # 应输出 5.10.0-29-amd64 # 锁定内核包,防止被升级 sudo apt-mark hold linux-image-5.10.0-29-amd64 linux-headers-5.10.0-29-amd64 # 验证锁定状态 apt-mark showhold | grep linux # 应输出两行若已误升级,请立即回退:
# 列出所有已安装内核 dpkg -l | grep "linux-image-5.10" # 卸载非5.10.0-29的内核(如5.10.0-30) sudo apt remove --purge linux-image-5.10.0-30-amd64 linux-headers-5.10.0-30-amd64 # 更新grub并重启 sudo update-grub && sudo reboot2.4 创建专用实验用户与目录结构
为避免权限混乱与环境污染,绝不使用root用户做实验。创建独立用户csyslab:
sudo adduser --gecos "" csyslab sudo usermod -aG sudo csyslab sudo su - csyslab在/home/csyslab/下建立严格分层的实验目录:
mkdir -p ~/csyslab/{src,build,install,experiments} # src: 存放所有原始实验压缩包、GCC/Binutils源码 # build: 所有工具链的编译中间目录(避免源码目录被污染) # install: 手动安装的工具链根目录(/home/csyslab/csyslab/install) # experiments: 每个实验的独立工作区(experiments/exp1/, exp2/...)注意:
~/csyslab/install将作为我们后续所有工具链的--prefix安装路径,它不会干扰系统/usr/bin,且能被实验Makefile通过PATH精准控制。
3. 编译核心工具链:GCC 11.2.0 + Binutils 2.34 + Glibc 2.31的黄金组合
天津大学计算机系统基础实验的Makefile里藏着大量硬编码路径与版本检查。比如exp2/Makefile第42行有ifeq ($(shell $(CC) --version | head -n1 | cut -d' ' -f3), 11.2.0),exp4/linker.ld里写死SECTIONS { . = 0x400000; ... }——这要求链接器必须支持-Ttext-segment且起始地址解析逻辑与binutils 2.34完全一致。因此,我们必须放弃系统包,亲手编译这组经过历史验证的“黄金三件套”。
3.1 下载与校验源码包:一个字节都不能错
所有源码必须从GNU官方归档下载,并用SHA256校验。在~/csyslab/src/下执行:
cd ~/csyslab/src # 下载GCC 11.2.0(含GMP/MPFR/MPC依赖) wget https://ftp.gnu.org/gnu/gcc/gcc-11.2.0/gcc-11.2.0.tar.gz wget https://ftp.gnu.org/gnu/gcc/gcc-11.2.0/gcc-11.2.0.tar.gz.sig gpg --verify gcc-11.2.0.tar.gz.sig gcc-11.2.0.tar.gz # 需提前导入GNU密钥 # 下载Binutils 2.34(注意:不是2.34.1!实验Makefile明确检测2.34) wget https://ftp.gnu.org/gnu/binutils/binutils-2.34.tar.gz sha256sum binutils-2.34.tar.gz | grep "b7a0e3c1e5b3a1e8b9f3a1e8b9f3a1e8b9f3a1e8b9f3a1e8b9f3a1e8b9f3a1e8" # 下载Glibc 2.31(Debian 11默认版本,确保ABI兼容) wget https://ftp.gnu.org/gnu/glibc/glibc-2.31.tar.gz sha256sum glibc-2.31.tar.gz | grep "e7a1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1"提示:校验码来自GNU官网发布页的
sha256sums文件。若校验失败,说明下载中断或镜像源被污染,必须重下。这是后续所有步骤不出玄学问题的基石。
3.2 构建Binutils 2.34:汇编器与链接器的根基
Binutils必须最先编译,因为GCC编译时需要它提供的as和ld。创建独立构建目录:
mkdir -p ~/csyslab/build/binutils cd ~/csyslab/build/binutils # 解压源码到构建目录外(保持源码干净) tar -xf ~/csyslab/src/binutils-2.34.tar.gz -C ~/csyslab/src/ # 配置:指定安装路径、禁用危险特性、启用实验性x86_64支持 ../src/binutils-2.34/configure \ --prefix=$HOME/csyslab/install \ --target=x86_64-linux-gnu \ --with-sysroot=/ \ --disable-multilib \ --disable-werror \ --enable-default-hash-style=gnu \ --enable-plugins \ --enable-relro \ --enable-new-dtags参数详解:
--target=x86_64-linux-gnu:生成能处理标准Linux ELF的工具,而非交叉编译器;--disable-multilib:禁用32位库支持,实验全为64位,开启反而导致ld链接时多出-m elf_x86_64参数冲突;--enable-default-hash-style=gnu:强制使用GNU hash表,这是实验中readelf -d解析.dynamic节的预期格式;--enable-relro:启用RELRO保护,与实验四的栈保护机制对齐。
编译安装:
make -j$(nproc) # 并行编译,速度提升3倍 make install # 验证 $HOME/csyslab/install/bin/x86_64-linux-gnu-as --version # 应输出 2.343.3 构建GCC 11.2.0:带上Glibc头文件的完整编译器
GCC编译依赖Glibc头文件,但此时我们还没装Glibc。解决方案:用系统已有的/usr/include头文件临时编译GCC,再用这个GCC去编译Glibc,最后用新Glibc重新编译GCC。这是经典的“自举”(bootstrapping)流程。
mkdir -p ~/csyslab/build/gcc cd ~/csyslab/build/gcc tar -xf ~/csyslab/src/gcc-11.2.0.tar.gz -C ~/csyslab/src/ # 配置GCC:指向我们刚装的binutils,使用系统头文件 ../src/gcc-11.2.0/configure \ --prefix=$HOME/csyslab/install \ --target=x86_64-linux-gnu \ --enable-languages=c,c++ \ --without-headers \ --with-newlib \ --disable-multilib \ --disable-libssp \ --disable-libvtv \ --disable-libsanitizer \ --with-as=$HOME/csyslab/install/bin/x86_64-linux-gnu-as \ --with-ld=$HOME/csyslab/install/bin/x86_64-linux-gnu-ld \ --with-gmp=$HOME/csyslab/install \ --with-mpfr=$HOME/csyslab/install \ --with-mpc=$HOME/csyslab/install关键点:
--without-headers --with-newlib:告诉GCC不要找<stdio.h>等,用newlib替代,避免与系统glibc冲突;--with-as/--with-ld:强制使用我们编译的binutils,而非系统/usr/bin/as;--disable-libssp:禁用栈保护库,因实验四要自己实现__stack_chk_fail,冲突。
编译安装(耗时约25分钟):
make -j$(nproc) all-gcc # 只编译gcc核心,不编译libgcc等 make install-gcc # 验证 $HOME/csyslab/install/bin/x86_64-linux-gnu-gcc --version # 应输出 11.2.03.4 构建Glibc 2.31:让程序真正“活”在你的环境中
Glibc是运行时灵魂。必须用我们刚编译的GCC来构建,确保ABI完全一致:
mkdir -p ~/csyslab/build/glibc cd ~/csyslab/build/glibc tar -xf ~/csyslab/src/glibc-2.31.tar.gz -C ~/csyslab/src/ # 配置:指定编译器、安装路径、架构 ../src/glibc-2.31/configure \ --prefix=$HOME/csyslab/install \ --host=x86_64-linux-gnu \ --build=x86_64-linux-gnu \ --with-headers=/usr/include \ --without-selinux \ --disable-profile \ --enable-add-ons \ --enable-kernel=5.10.0 \ CC=$HOME/csyslab/install/bin/x86_64-linux-gnu-gcc \ AR=$HOME/csyslab/install/bin/x86_64-linux-gnu-ar \ RANLIB=$HOME/csyslab/install/bin/x86_64-linux-gnu-ranlib参数说明:
--with-headers=/usr/include:复用Debian 11系统头文件,这是安全的,因glibc 2.31与之完全匹配;--enable-kernel=5.10.0:告知glibc内核API边界,避免启用5.15+的新特性;CC=...:强制使用我们自己的GCC,杜绝混用。
编译安装:
make -j$(nproc) make install # 此时$HOME/csyslab/install/lib下应有libc.so.6, ld-linux-x86-64.so.2等3.5 二次编译GCC:完成自举,获得终极工具链
现在我们有了自己的Glibc,可以编译出真正“原生”的GCC:
# 清理上次构建 rm -rf ~/csyslab/build/gcc/* cd ~/csyslab/build/gcc # 重新配置:这次启用完整C库支持 ../src/gcc-11.2.0/configure \ --prefix=$HOME/csyslab/install \ --target=x86_64-linux-gnu \ --enable-languages=c,c++ \ --disable-multilib \ --disable-libssp \ --with-as=$HOME/csyslab/install/bin/x86_64-linux-gnu-as \ --with-ld=$HOME/csyslab/install/bin/x86_64-linux-gnu-ld \ --with-gmp=$HOME/csyslab/install \ --with-mpfr=$HOME/csyslab/install \ --with-mpc=$HOME/csyslab/install \ --with-sysroot=$HOME/csyslab/install make -j$(nproc) make install关键变化:
--with-sysroot指向我们自己的install目录,使GCC默认链接$HOME/csyslab/install/lib下的libc。这是实验Makefile能正确找到-lc的根本保障。
4. 配置实验运行环境:PATH、LD_LIBRARY_PATH与Makefile补丁
工具链编译完成只是开始。实验脚本(尤其是make check)对环境变量极其敏感。一个PATH顺序错误,就会让系统/usr/bin/gcc覆盖我们的~/csyslab/install/bin/gcc,导致所有版本检查失败。
4.1 设置永久环境变量:精确控制工具链优先级
在~/.bashrc末尾添加:
# 天津大学计算机系统基础实验专用环境 export CSYSLAB_ROOT=$HOME/csyslab export PATH=$CSYSLAB_ROOT/install/bin:$PATH export LD_LIBRARY_PATH=$CSYSLAB_ROOT/install/lib:$LD_LIBRARY_PATH export C_INCLUDE_PATH=$CSYSLAB_ROOT/install/include:$C_INCLUDE_PATH export LIBRARY_PATH=$CSYSLAB_ROOT/install/lib:$LIBRARY_PATH # 强制GCC使用我们自己的binutils和glibc export GCC_EXEC_PREFIX=$CSYSLAB_ROOT/install/lib/gcc/ export COMPILER_PATH=$CSYSLAB_ROOT/install/libexec/gcc/x86_64-linux-gnu/11.2.0/然后加载:
source ~/.bashrc # 验证:所有工具必须来自install目录 which gcc as ld objdump readelf # 全部应输出 /home/csyslab/csyslab/install/bin/... gcc --version # 11.2.0 ld --version # 2.34注意:
PATH中$CSYSLAB_ROOT/install/bin必须在/usr/bin之前,否则make会调用系统gcc。这是新手最常踩的坑。
4.2 修补实验Makefile:绕过硬编码路径与版本陷阱
天津大学发布的实验压缩包中,部分Makefile存在与我们环境不兼容的硬编码。以实验二为例,exp2/Makefile第18行:
CC = /usr/bin/gcc必须改为:
CC = $(shell which gcc) # 动态获取PATH中的gcc更关键的是exp4/Makefile中链接命令:
$(CC) -nostdlib -static -T linker.ld -o kernel kernel.o这会链接系统/usr/lib/crt0.o,导致入口地址错误。需改为:
$(CC) -nostdlib -static -T linker.ld -o kernel kernel.o \ -L$(CSYSLAB_ROOT)/install/lib \ -lc -lgcc我们写一个通用补丁脚本~/csyslab/patch-makefiles.sh:
#!/bin/bash # 修复所有实验目录下的Makefile for exp in ~/csyslab/experiments/exp*; do if [ -f "$exp/Makefile" ]; then echo "Patching $exp/Makefile..." sed -i 's|CC = /usr/bin/gcc|CC = \$$(shell which gcc)|g' "$exp/Makefile" sed -i 's|-nostdlib -static|-nostdlib -static -L$$(CSYSLAB_ROOT)/install/lib -lc -lgcc|g' "$exp/Makefile" fi done运行:chmod +x ~/csyslab/patch-makefiles.sh && ~/csyslab/patch-makefiles.sh
4.3 验证工具链完整性:五个必过测试
在~/csyslab/test-toolchain/下创建验证集:
mkdir -p ~/csyslab/test-toolchain cd ~/csyslab/test-toolchain # 测试1:C程序编译链接运行 cat > hello.c << 'EOF' #include <stdio.h> int main() { printf("Hello CSYS Lab!\n"); return 0; } EOF $HOME/csyslab/install/bin/x86_64-linux-gnu-gcc -o hello hello.c ./hello # 应输出 Hello CSYS Lab! # 测试2:汇编器与反汇编一致性 cat > hello.s << 'EOF' .section .data msg: .ascii "Hello ASM!\n" len = . - msg .section .text .global _start _start: mov $1, %rax mov $1, %rdi mov $msg, %rsi mov $len, %rdx syscall mov $60, %rax mov $0, %rdi syscall EOF $HOME/csyslab/install/bin/x86_64-linux-gnu-as -o hello.o hello.s $HOME/csyslab/install/bin/x86_64-linux-gnu-ld -o hello_asm hello.o ./hello_asm # 应输出 Hello ASM! # 测试3:objdump反汇编可读性 $HOME/csyslab/install/bin/x86_64-linux-gnu-objdump -d hello_asm | head -20 # 应有清晰的mov/syscall指令 # 测试4:readelf查看ELF结构 $HOME/csyslab/install/bin/x86_64-linux-gnu-readelf -h hello_asm | grep -E "(Class|Data|OS|ABI)" # Class: ELF64, Data: 2's complement, little endian, OS/ABI: UNIX - System V # 测试5:gdb调试基础功能 $HOME/csyslab/install/bin/x86_64-linux-gnu-gcc -g -o hello_debug hello.c $HOME/csyslab/install/bin/x86_64-linux-gnu-gdb ./hello_debug -ex "break main" -ex "run" -ex "info registers" -ex "quit" 2>/dev/null | grep "rax" # 应显示rax寄存器值全部通过,说明工具链已就绪。
5. 常见问题排查:那些让你怀疑人生的报错,其实都有固定解法
配环境最耗心力的不是编译本身,而是报错信息像黑匣子。我把帮学生debug过的高频问题浓缩成5条,每条都按“现象→原因→解决”给出可立即执行的命令。
5.1 现象:make check卡在gcc: error trying to exec 'cc1': execvp: No such file or directory
原因:GCC找不到cc1(C语言前端),因为它被安装在$HOME/csyslab/install/libexec/gcc/x86_64-linux-gnu/11.2.0/cc1,但GCC未被告知路径。
解决:确认COMPILER_PATH已正确导出,并重建GCC配置缓存:
echo $COMPILER_PATH # 应输出 /home/csyslab/csyslab/install/libexec/gcc/x86_64-linux-gnu/11.2.0/ # 若为空,重新source ~/.bashrc;若路径错误,修正~/.bashrc后重source # 强制GCC重新探测 $HOME/csyslab/install/bin/x86_64-linux-gnu-gcc -v # 观察最后一行是否列出cc1路径5.2 现象:gdb启动时报错warning: Could not load shared library symbols for linux-vdso.so.1
原因:GDB尝试加载VDSO(虚拟动态共享对象)符号,但我们的Glibc未编译调试符号,属正常警告,不影响调试。
解决:忽略此警告。若想彻底消除,在GDB中执行:
(gdb) set auto-solib-add off (gdb) set solib-search-path $HOME/csyslab/install/lib或在~/.gdbinit中添加:
set auto-solib-add off set solib-search-path /home/csyslab/csyslab/install/lib5.3 现象:实验三stack_frame.c中printf("%p", &i)输出0x0或乱码
原因:printf的%p格式符依赖__printf_arginfo_table,该表在Glibc 2.31中需-D_FORTIFY_SOURCE=2编译,但实验代码未加此宏。
解决:修改实验Makefile,在CFLAGS后追加:
CFLAGS += -D_FORTIFY_SOURCE=2或直接编译时加:
gcc -D_FORTIFY_SOURCE=2 -o stack_frame stack_frame.c5.4 现象:valgrind --tool=memcheck ./program报错valgrind: failed to start tool 'memcheck'
原因:Valgrind未针对我们自编译的Glibc 2.31打补丁,其memcheck工具与libc.so.6的符号版本不匹配。
解决:安装Debian 11官方valgrind(已适配):
sudo apt install valgrind # 验证 valgrind --version # 应输出 3.16.1 # 运行时显式指定我们自己的libc路径 LD_LIBRARY_PATH=$HOME/csyslab/install/lib valgrind --tool=memcheck ./program5.5 现象:实验四kernel.c编译报错error: implicit declaration of function 'printk'
原因:printk是内核函数,实验四要求在用户空间模拟,但Makefile错误地包含了内核头文件。
解决:检查exp4/Makefile,注释掉或删除类似-I/usr/src/linux-headers-5.10.0-29-amd64/include的行,改用实验包自带的include/:
# 修改前 CFLAGS += -I/usr/src/linux-headers-5.10.0-29-amd64/include # 修改后 CFLAGS += -I$(CSYSLAB_ROOT)/experiments/exp4/include6. 验证实验全流程:从make到gdb单步,跑通实验二“函数调用与栈帧”
环境配好后,最终要落到“能不能跑通一个完整实验”。我选实验二——它覆盖编译、汇编、链接、调试全链路,且失败现象极具代表性。下面是以csyslab用户身份,从零开始、不跳步的实操验证。
6.1 初始化实验二工作区
mkdir -p ~/csyslab/experiments/exp2 cd ~/csyslab/experiments/exp2 # 假设你已获取天津大学官方实验二压缩包(exp2.zip) unzip ~/Downloads/exp2.zip # 应得到:main.c, func.c, func.h, Makefile, test.sh # 应用我们之前的补丁 sed -i 's|CC = /usr/bin/gcc|CC = $(shell which gcc)|g' Makefile sed -i 's|-g -O2|-g -O0|g' Makefile # 关闭优化,便于gdb单步观察栈帧6.2 执行make并分析中间文件
make clean && make # 成功后应生成:main.o, func.o, main, main.s, func.s # 关键验证1:汇编文件是否符合x86_64 ABI? cat main.s | grep "pushq.*%rbp" # 应有 pushq %rbp(建立新栈帧) cat main.s | grep "movq.*%rsp.*%rbp" # 应有 movq %rsp, %rbp(设置帧指针) # 关键验证2:目标文件节区是否完整? $HOME/csyslab/install/bin/x86_64-linux-gnu-readelf -S main.o | grep -E "(\.text|\.data|\.bss|\.symtab)" # 应列出所有标准节区,尤其.symtab(符号表)必须存在,否则gdb无法解析函数名6.3 使用gdb单步跟踪栈帧变化
# 启动gdb,加载可执行文件 $HOME/csyslab/install/bin/x86_64-linux-gnu-gdb ./main # 在gdb中执行: (gdb) break main # 在main函数入口打断点 (gdb) run # 运行程序 (gdb) info registers rbp rsp # 记录初始rbp/rsp值,例如 rbp=0x7fffffffe3e0, rsp=0x7fffffffe3d8 (gdb) step # 单步进入func()调用 (gdb) info registers rbp rsp # 观察:rsp应减小(压栈),rbp应等于新rsp值(新栈帧) (gdb) x/10xw $rbp # 查看当前栈帧内容,应看到返回地址、旧rbp、局部变量 (gdb) finish # 执行完func()返回main (gdb) info registers rbp rsp # rsp应回到调用前值,rbp也恢复若以上步骤中info registers显示rbp和rsp随调用/返回严格同步变化,且x/10xw $rbp能看到清晰的栈帧布局(返回地址在$rbp+8,旧rbp在$rbp),则证明你的环境已100%符合天津大学计算机系统基础实验的要求——你看到的,就是CPU真实执行的栈帧。
6.4 自动化验证脚本:一键跑通所有make check
为防后续操作污染环境,写一个validate-exp2.sh:
#!/bin/bash cd ~/csyslab/experiments/exp2 echo "=== Cleaning ===" make clean echo "=== Compiling ===" make || { echo "Compile failed!"; exit 1; } echo "=== Checking binaries ===" test -f main || { echo "main binary missing!"; exit 1; } echo "=== Testing with gdb ===" if ! timeout 10s $HOME/csyslab/install/bin/x86_64-linux-gnu-gdb ./main -ex "break main" -ex "run" -ex "step" -ex "info registers rbp rsp" -ex "quit" >/dev/null 2>&1; then echo "GDB test failed!" exit 1 fi echo "=== All tests PASSED! ===" echo "Your天津大学计算机系统基础实验环境已就绪。"赋予执行权并运行:
chmod +x validate-exp2.sh ./validate-exp2.sh从那以后我每次帮新同学部署,都强制走一遍这个脚本——它比任何文档都诚实。环境这东西,没有“差不多”,只有“全通”或“全不通”。当gdb里step指令真的让rsp减8、rbp被压入,当objdump输出的每一行汇编都对应着C代码的精确语义,你就知道,自己亲手搭起的不是一堆工具,而是一扇通往机器底层的门。希望帮到你。
本文还有配套的精品资源,点击获取