You need to enable JavaScript to run this app. Linux汇编程序调用sysinfo返回成功但结构体未被修改的问题排查
优惠活动
大模型
产品
解决方案
定价
更多

Linux汇编程序调用sysinfo返回成功但结构体未被修改的问题排查

问题根因

你遇到的现象完全是地址错配导致的,和syscall本身的逻辑没有关系:

  • sysinfo系统调用本身是成功执行的:你传入的内存地址是合法可写的,内核已经把完整的结构体数据写入了那块内存,所以strace能读到正确的uptime、内存总量这些值,系统调用返回值rax=0也印证了没有执行错误。
  • 你在gdb里看到全0,是因为gdb查询&result时用的符号地址,根本不是你传给系统调用的那个缓冲区的真实地址。

地址错配的形成原因

现在主流Linux发行版默认生成PIE(位置无关可执行文件),你的代码踩了两个写汇编时的常见坑:

  • 全局符号绑定冲突:你没有把result标记为本地私有符号,这个名字会被导出到全局动态符号表。程序加载时,动态链接器会把gdb中显示的result符号绑定到共享库映射区域的同名符号上——也就是你看到的0x7ffff7faad80,这个地址属于共享库的只读映射段,根本不是你自己程序的数据区。
    但你代码里写leaq result(%rip), %rdi取地址的时候,是编译时基于RIP相对偏移直接算出的你自己程序data段里的真实缓冲区地址,这个过程完全不依赖动态链接的符号绑定逻辑,所以传给内核的是正确的可写地址,内核自然能正常写入数据。
  • 你自己拆分标签定义的结构体和内核实际的sysinfo内存布局没有对齐,但这不是内存全0的原因——只要缓冲区是连续、长度足够、权限可写,内核就会正常写入全部数据,和你怎么给字段打标签没有关系。

验证和修复方法

  • 验证方式:在gdb里直接打印$rdi的值(也就是syscall的第一个参数),和&result的值做对比,会发现两个地址完全不重合。
  • 修复方案:
    • 在result定义前加.local result,把它标记为本地私有符号,不要导出到全局符号表,避免动态链接时的绑定冲突
    • 这类零初始化的缓冲区本来就该放在.bss段,不要放在.data段,直接用.comm result, 128, 16预留128字节的对齐缓冲区,就足够覆盖当前内核的sysinfo结构体大小,不用拆成零散的.quad定义

内容的提问来源于stack exchange,提问作者KMG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.05 15:36:03