设备队列、汇编与 IR

共 43 题
#

1. 为什么多数优化器以 IR(如 LLVM IR、GCC GIMPLE)而非机器码作为主要优化对象?

A 机器码优化比 IR 优化更通用
B IR 保留高层语义且目标无关,一套优化覆盖多架构;机器码层仍做指令选择与寄存器分配等目标特有优化 ✓ 正确答案
C IR 优化只能用于单一架构
D IR 优化与源码结构无关
#

2. 设计实验,在 Linux 用 fio 对比 deadline vs bfq vs none 调度器在 SSD 上的 P99?

A 实验应固定设备与负载仅切换调度器,用 clat 的 P99/P99.9 度量,多轮重复取稳定值;SSD 上 none 通常最优 ✓ 正确答案
B 调度器对比不需要控制负载参数
C bfq 在任何负载下延迟都最低
D P99 单次测量即可得出结论
#

3. ELF 目标文件的 .text/.data/.bss/.rodata 节区分别存放什么,.bss 为何不占用文件空间?

A .rodata 映射为可写
B .bss 也保存初值
C .text 存指令、.rodata 存只读常量、.data 存已初始化数据、.bss 存未初始化数据;.bss 为零初值且以 NOBITS 描述,不占文件空间 ✓ 正确答案
D .data 中的数据在加载时不保留初值
#

4. 汇编伪指令(如 .globl、.align、.section、.quad)与真实机器指令的区别是什么,汇编器如何展开它们?

A .align 只影响注释
B 伪指令与机器指令等价
C .globl 会产生一条机器指令
D 伪指令是给汇编器的命令,不产生执行语义:.globl 导出符号、.align 对齐填充、.quad 生成 8 字节数据 ✓ 正确答案
#

5. 调用者保存(caller-saved)与被调用者保存(callee-saved)寄存器如何在函数调用间划分责任?

A caller-saved 寄存器被调函数不能使用
B callee-saved 寄存器由被调函数负责保存恢复,caller-saved 寄存器由调用者按需保存,寄存器分配据此决策 ✓ 正确答案
C callee-saved 寄存器调用前后值一定变化
D 参数寄存器属于 callee-saved
#

6. 目标文件中的重定位节(.rela.text)记录了什么信息,为何汇编阶段无法确定绝对地址?

A .rela.text 存储机器指令本身
B 汇编器可以直接确定所有绝对地址
C 汇编阶段外部符号与最终布局未知,故以 .rela.text 记录位置、符号、类型与 addend,由链接器按最终地址修补 ✓ 正确答案
D 重定位只发生在静态链接
#

7. 栈对齐(16 字节)要求为何是 ABI 强制的,违反它对 SSE 指令与调用有何后果?

A System V ABI 要求 call 前 rsp 16 字节对齐,因 movaps 等对齐访存指令需对齐,违规触发 #GP ✓ 正确答案
B 栈对齐只影响性能不影响正确性
C movaps 不要求操作数对齐
D 编译器会自动修复所有违规调用
#

8. SSA 形式中 φ 函数为何要在控制流汇合点插入?它解决了多条路径赋值到同一变量带来的什么问题?

A φ 只在顺序代码中插入
B φ 函数产生机器码
C 汇合点多条路径给同一变量带来多个版本,φ 函数按来路合并版本,恢复每变量单赋值,简化 def-use 链 ✓ 正确答案
D φ 函数不影响数据流分析
#

9. 为什么 SSA 保证每个变量只被赋值一次后,常量传播与死代码消除的实现会显著简化?

A SSA 下每个 use 对应唯一 def,常量传播沿 use 链前向求值、死代码靠 use 计数为 0 判定,免去迭代数据流求解 ✓ 正确答案
B SSA 使常量传播需要更多迭代
C SSA 下死代码无法识别
D φ 节点使 def-use 关系更模糊
#

10. 公共子表达式消除(CSE)依赖哪种数据流信息?局部 CSE 与全局 CSE 分别在什么范围内进行?

A CSE 不考虑内存读写副作用
B CSE 只做局部优化
C 全局 CSE 使用后向数据流分析
D CSE 依赖可用表达式信息:局部 CSE 在块内扫描哈希表,全局 CSE 需前向数据流分析跨块传播 ✓ 正确答案
#

11. 强度削减如何借助归纳变量把循环内的乘法替换为累加?它对地址计算优化有何意义?

A 强度削减会增加循环内指令数
B 强度削减只适用于浮点运算
C 归纳变量与循环无关
D 强度削减把循环内与归纳变量相关的乘法替换为增量累加,地址计算可转为指针递增,减少指令延迟 ✓ 正确答案
#

12. 寄存器分配的图着色算法为何是 NP 完全问题?当物理寄存器(颜色)不够时,溢出(spill)到内存的代价如何衡量?

A 溢出只影响代码体积不影响性能
B 图着色寄存器分配是多项式可解的
C 溢出不会增加指令数
D 寄存器分配等价于图 k-着色,一般图 k-着色是 NP 完全,故用启发式近似;溢出代价按循环频率与可重算性加权 ✓ 正确答案
#

13. 内联展开在消除调用开销的同时带来代码膨胀,编译器常用哪些启发式(调用频率、函数体大小)控制膨胀?

A 内联用成本模型权衡:函数体大小与调用点数量乘积、调用频率、递归深度、栈帧大小都是膨胀控制启发式 ✓ 正确答案
B 内联总是提升性能,应尽量多用
C 内联不会增加代码体积
D 内联对递归函数无任何限制
#

14. 死代码消除如何判断某条指令的结果永不被使用?带副作用的调用为何不能当作死代码删除?

A volatile 读可以安全删除
B 无 use 的调用都可以删除
C DCE 不考虑副作用
D DCE 删除结果无 use 且无副作用的指令;调用因可能写内存、抛异常等副作用而不可随意删除 ✓ 正确答案
#

15. 常量折叠与常量传播的区别是什么?它们在 IR 上为何常常迭代进行?

A 常量传播只需执行一遍
B 折叠与传播是同一变换
C 折叠对单条全常量指令求值,传播把常量 def 替换到 use;传播制造新常量、折叠求值,交替迭代到不动点 ✓ 正确答案
D 折叠能处理含变量操作数
#

16. 静态链接的符号解析与重定位是两个独立阶段,它们各自解决什么问题,为什么重定位必须在符号解析之后才能完成?

A 符号解析决定段布局
B 重定位不依赖符号解析
C 符号解析把引用绑定到定义,重定位按解析结果与最终段布局计算地址;重定位依赖解析确定的定义位置,故必须后行 ✓ 正确答案
D 两个阶段可任意交换顺序
#

17. 强符号与弱符号同名冲突时链接器遵循什么取舍规则,出现多个弱符号时又如何决定最终归属?

A 多个强符号同名会自动合并
B 弱符号与强符号同名时弱符号胜出
C 强符号与弱符号同名时强定义胜出,多个弱符号任选其一,弱引用允许无定义存在 ✓ 正确答案
D 弱引用无定义时链接报错
#

18. 可重定位目标文件中的 R_X86_64_PC32、R_X86_64_PLT32、R_X86_64_GOTPCREL 等重定位类型分别用在什么场合?

A GOTPCREL 用于函数调用
B 三种类型都用于直接寻址
C PC32 用于直接 PC 相对寻址,PLT32 用于经 PLT 调用动态函数(懒绑定),GOTPCREL 用于 PIC 下经 GOT 间接访问全局数据 ✓ 正确答案
D PLT32 与懒绑定无关
#

19. 链接器脚本(linker script)如何控制段布局与符号地址,-Ttext 与 SECTIONS 对嵌入式裸机程序意味着什么?

A 裸机程序的运行地址由操作系统决定
B 链接器脚本只能设置输出文件名
C -Ttext 只影响动态链接
D 链接器脚本用 SECTIONS 控制段地址、对齐与组成,并定义 __bss_start 等锚点符号;裸机程序靠 -Ttext/脚本钉死入口与内存布局 ✓ 正确答案
#

20. 静态链接与动态链接在启动时间、运行时内存共享和版本升级灵活性上各有哪些取舍?

A 动态链接的代码段不能共享
B 动态链接启动总是快于静态
C 静态链接支持库的热升级
D 静态链接启动快、无运行依赖,但内存不共享且升级需重链;动态链接共享库代码页并支持热升级,代价是启动解析与依赖管理 ✓ 正确答案
#

21. 系统调用 ABI,x86-64 中 syscall 指令如何传参(rax 存编号、rdi/rsi/rdx/r10/r8/r9 存参数),内核如何把 -errno 编码返回给用户态?

A syscall 指令不破坏任何寄存器
B syscall 第 4 个参数用 rcx 传递
C 内核返回错误码为正数
D syscall 以 rax 存调用号、rdi/rsi/rdx/r10/r8/r9 传参,返回时 rax 为负表示 -errno,由 libc 转为 errno 并返回 -1 ✓ 正确答案
#

22. 静态库(.a)按成员归档,链接时为何会出现成员顺序依赖,--start-group/--end-group 如何解决循环引用?

A 静态库按需提取且只扫描一遍,循环引用会导致符号未解析;--start-group/--end-group 组内循环扫描直到无新解析 ✓ 正确答案
B 静态库成员总是全部链接
C 链接顺序不影响静态库
D --start-group 会增加运行时开销
#

23. 动态链接器 ld-linux.so 在启动时如何完成依赖库加载、符号查找与重定位,LD_BIND_NOW 与 RELRO 改变了什么?

A LD_BIND_NOW 会降低启动时间
B 懒绑定在启动时完成全部解析
C ld.so 递归加载 DT_NEEDED 库并做符号解析与重定位;LD_BIND_NOW 禁用懒绑定提前解析,配合 RELRO 使 GOT 只读 ✓ 正确答案
D RELRO 与 GOT 权限无关
#

24. TLS 的 General Dynamic 与 Initial Exec 访问模型在动态链接与静态链接下的开销差异来自哪里?

A GD 的访问开销为一次立即数加法
B IE 支持 dlopen 加载的模块
C GD 每次访问经 __tls_get_addr 动态查找(支持 dlopen),IE 由加载期解析偏移后直接访问,静态链接可用 LE 零查找 ✓ 正确答案
D 两种模型开销完全相同
#

25. System V AMD64 调用约定下函数序言(push rbp; mov rbp,rsp; sub rsp,N)与尾声如何搭建和拆除栈帧?

A 序言的 sub rsp,N 分配的是参数空间
B leave 只恢复 rsp 不恢复 rbp
C 序言 push rbp 保存旧帧、mov rbp,rsp 设帧底、sub rsp,N 分配局部区;leave(mov rsp,rbp; pop rbp)+ret 还原并返回 ✓ 正确答案
D ret 从 rbp 指向的位置弹出返回地址
#

26. leave 与 ret 指令分别完成栈帧拆除的哪一步,红区(red zone)在叶子函数中为何可被安全使用?

A leave 直接执行返回跳转
B leave 释放局部空间并恢复 rbp,ret 弹出返回地址跳转;红区是 rsp 下方 128 字节,叶函数可安全用作临时存储 ✓ 正确答案
C 红区可以被信号处理程序写入
D 非叶函数也能无条件使用红区
#

27. 循环不变量外提(LICM)把计算移出循环体需要满足哪些安全性条件?为什么不能随意移动可能抛异常的指令?

A LICM 不需要别名分析
B 只要表达式每次值相同就可以外提
C 异常指令外提不会改变程序行为
D LICM 外提需满足不变量、支配、无副作用与异常安全四条件;可能抛异常的指令外提会改变异常时机,故保守不移动 ✓ 正确答案
#

28. PLT 与 GOT 如何协作实现动态函数的延迟绑定(lazy binding),第一次调用与后续调用走过的路径有何不同?

A 首次与后续调用路径完全相同
B 首次调用经 PLT stub 跳 GOT 初值(回指 stub)触发 _dl_runtime_resolve 解析并回填 GOT;后续调用经已回填 GOT 直跳真实函数 ✓ 正确答案
C GOT 项初始值就是真实函数地址
D 懒绑定在启动时完成全部解析
#

29. _exit 与 exit 在 C 程序退出时的清理顺序有何差异,atexit 与 atfork 钩子分别在何时触发?

A _exit 也会运行 atexit 处理器
B exit() 逆序运行 atexit、flush stdio 后 _exit;_exit 直接系统调用终止不清理缓冲;atfork 钩子在 fork 前/父/子三处触发 ✓ 正确答案
C atfork 在程序退出时触发
D exit() 不刷新 stdio 缓冲
#

30. Linux request queue 在块设备层(bio)的角色?

A request queue 只用于排序不用于合并
B bio 直接发给设备
C bio 描述页向量与扇区范围的逻辑 I/O,块层把可合并的 bio 组装成 request 并经 request queue 调度下发 ✓ 正确答案
D request 与 bio 无关
#

31. Linux tc qdisc(queuing discipline)在网络出口的流量整形?

A tbf 不能限制平均速率
B qdisc 只用于入口流量
C qdisc 挂在设备出口控制排队与发送时机,tbf/htb 按令牌桶限速整形,fq_codel 提供公平队列与 AQM ✓ 正确答案
D 默认 qdisc 是 noqueue
#

32. Linux 中 cfq deadline noop 三种调度器在背压中的差异?

A 三种调度器行为完全相同
B noop/none 近 FIFO 直通、背压直接;deadline 按截止时间保延迟有界;cfq/bfq 按进程公平分配时间片,背压传导慢但公平 ✓ 正确答案
C deadline 不区分读写
D cfq 适合延迟敏感数据库
#

33. 为何 credit-based 流量控制(RoCE、InfiniBand)优于 pause frame?

A pause frame 不存在死锁风险
B pause frame 支持逐队列精确流控
C credit-based 不需要接收端反馈
D credit-based 按接收缓冲额度精确控制发送,避免 pause frame 暂停整端口带来的 HOL 阻塞与无关流波及 ✓ 正确答案
#

34. 推导为何 NIC Rx ring buffer 满时 NIC 丢包而 paused?

A Rx ring 满时 NIC 无可用 DMA 目标只能丢包,成因是消费速度低于到达速率;缓解靠多队列、加大 ring、NAPI 预算与 busy poll ✓ 正确答案
B ring 满时包会等待而不是丢弃
C rx_missed 表示 CPU 处理丢包
D 加大 ring 无任何副作用
#

35. -fomit-frame-pointer 为何能省出 rbp 寄存器,被省略的调用链如何用 .eh_frame(DWARF unwind 信息)恢复?

A .eh_frame 只在调试构建中生成
B 省略帧指针后无法再回溯调用栈
C rbp 释放后局部变量无法寻址
D -fomit-frame-pointer 释放 rbp 供计算使用、减少序言指令,栈回溯改由 .eh_frame 的 CFI 信息按 RIP 查 FDE 恢复 ✓ 正确答案
#

36. x86-64 指令编码中的 REX 前缀与 ModRM 字段如何扩展寄存器编号,为什么 r8-r15 需要额外前缀位?

A REX 前缀在 32 位模式下也可用
B REX 前缀只影响操作数大小
C r8-r15 使用与 rax-rbx 相同的短编码
D ModRM 的 reg/rm 各 3 位只能编码 8 寄存器,REX 前缀的 R/X/B 位扩展出第 4 位,从而覆盖 r8-r15 ✓ 正确答案
#

37. 调用约定中前六个整型参数用 rdi/rsi/rdx/rcx/r8/r9 传递,超出部分与返回值如何在栈和 rax 上处理?

A 所有参数都通过栈传递
B 前六个整型参数经 rdi/rsi/rdx/rcx/r8/r9 传递,第七个起压栈;返回整型用 rax,浮点用 xmm0 ✓ 正确答案
C 返回值最多 32 位
D 浮点参数占用整型寄存器通道
#

38. 宏汇编与条件汇编在预处理期如何展开,它与 C 预处理器宏在展开时机上有何异同?

A 汇编宏与 C 宏都是编译/汇编前的文本替换;汇编宏由汇编器处理并可嵌套与生成唯一局部符号,C 宏由 cpp 处理且支持 #/## 操作符 ✓ 正确答案
B 汇编宏在运行时展开
C C 宏在语法分析之后展开
D 条件汇编属于运行期分支
#

39. 优化 pass 的执行顺序为何会影响最终效果?举例说明一个 pass 可能使另一个 pass 的机会消失。

A 每个 pass 相互独立可任意排序
B pass 顺序对结果无影响
C pass 间存在机会创造与破坏关系,如内联为常量传播创造机会、过早 CSE 会破坏后续折叠机会,故流水线顺序需精心编排 ✓ 正确答案
D 优化档位与 pass 顺序无关
#

40. 位置无关代码(PIC)为什么必须通过 GOT 间接寻址访问全局数据,直接寻址会破坏共享库的什么特性?

A PIC 直接编码绝对地址
B PIC 经 GOT 间接寻址全局数据,加载时由 ld.so 按实际基址填充,保持任意基址加载、符号覆盖与指令页共享 ✓ 正确答案
C GOT 寻址比直接寻址更快
D PIC 只影响数据不影响函数
#

41. C++ 的 vague linkage 为何会让虚表与内联函数在多个目标文件中重复定义,COMDAT/section group 如何完成去重?

A vtable 与内联函数按 vague linkage 每 TU 生成一份,编译器放入 COMDAT 组,链接器按签名符号只保留一份完成去重 ✓ 正确答案
B 多份 vtable 会触发重复定义错误
C COMDAT 组不保证完整性
D 内联函数不允许重复生成
#

42. 命名空间与 cgroup 在隔离范围(视图 vs 资源)上的根本区别是什么,PID 命名空间为何让进程可拥有独立 1 号?

A 命名空间与 cgroup 功能重复
B cgroup 也能隔离进程视图
C PID namespace 内的 1 号进程是宿主机的 PID 1
D namespace 隔离视图(进程树/网络/挂载),cgroup 限制资源用量;PID namespace 内从 1 重新编号,首进程承担容器 init 语义 ✓ 正确答案
#

43. 分支预测的工程手段,__builtin_expect(likely/unlikely)如何影响代码布局,BTB 溢出对分支预测性能有何影响?

A BTB 容量无限
B __builtin_expect 直接控制 CPU 预测器
C __builtin_expect 让编译器把热路径排成直落布局、冷路径跳转,改善取指;BTB 容量有限,分支目标过多会溢出导致预测失败惩罚 ✓ 正确答案
D likely 只影响语法不影响布局