You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

x86汇编线性搜索程序触发段错误求助:排查问题与概念盲区咨询

你的线性搜索汇编段错误根源与修复方案

兄弟,你的代码触发段错误+逻辑错误主要来自几个x86-64汇编的常见盲区,咱们一步步拆解并修复:

1. 核心问题:完全忽略了x86-64的调用约定

你用的是Linux/macOS默认的System V AMD64调用约定,前三个函数参数是存在固定寄存器里的:

  • 第一个参数(数组指针)→ rdi
  • 第二个参数(数组大小)→ rsi
  • 第三个参数(目标值)→ rdx

但你直接就push rbx/r12/r13,却完全没把实际参数的值加载到这些寄存器里!这导致rbx(你以为是数组指针)里是随机垃圾值,当你尝试访问[rbx+4*r14]时,必然会访问非法内存,触发段错误。

修复:在push寄存器后,把参数赋值给你要使用的寄存器:

push rbx ; 保存调用者寄存器(rbx是调用者保存的,必须保存)
push r12
push r13
; 把调用约定的参数加载到我们的工作寄存器
mov rbx, rdi    ; rbx = 数组指针
mov r12, rsi    ; r12 = 数组大小
mov r13, rdx    ; r13 = 目标值

2. 死代码导致初始化逻辑失效

你在xor rax, rax之后直接jmp loop,后面的mov r14, 0和mov r10, rbx根本不会被执行!虽然你用xor r14, r14初始化了计数器,但r10初始是0,而不是数组第一个元素的值,第一次循环的cmp r10, r13是在拿0和目标值比较,逻辑完全错误。

修复:删掉那个多余的jmp loop,让代码顺序执行进入循环,或者把初始化代码放在jmp之前。

3. 混淆了「数组元素值」和「索引」

你的end标签里,把r10(你用来存当前元素值的寄存器)赋值给rax返回,但题目要求返回的是找到目标的索引,不是元素值!而且你在循环里mov r10, [rbx+4*r14]是加载元素值,不是索引,这完全不符合需求。

修复:返回时把计数器r14(它正好是当前遍历的索引)赋值给rax。

4. 循环顺序错误导致第一个元素被跳过

你现在的循环流程是:先判断计数器是否越界→比较r10(初始0)和目标→递增计数器→加载下一个元素。这会导致第一个元素根本没被正确读取就进行比较,直接跳过了第一个元素的判断。

修复:调整循环顺序,先加载当前索引的元素,再进行比较:


修复后的完整代码

section .text
; function should return the index at which the target was found
; Parameter 1 is a pointer to the int array → rdi
; Parameter 2 is the size of the array → rsi
; Parameter 3 is the target element to find in the array → rdx
linearSearch:
	push rbx ; 保存调用者寄存器
	push r12
	push r13
	; 加载参数到工作寄存器
	mov rbx, rdi    ; rbx = 数组指针
	mov r12, rsi    ; r12 = 数组大小
	mov r13, rdx    ; r13 = 目标值
	xor r14, r14    ; r14 = 遍历索引,初始0
	xor rax, rax    ; 初始化返回值
loop:
	cmp r14, r12    ; 检查索引是否超过数组大小
	jae endNotFound ; 索引 >= 大小,说明没找到
	; 加载当前索引对应的数组元素
	mov r10d, [rbx + 4*r14] ; 注意用r10d,因为是int(32位)
	cmp r10d, r13d  ; 比较当前元素和目标值(都是32位int)
	je endFound     ; 找到目标,跳转到返回逻辑
	inc r14         ; 索引+1,继续循环
	jmp loop
endNotFound:
	mov rax, -1     ; 没找到返回-1
	; 恢复寄存器并返回
	pop r13
	pop r12
	pop rbx
	ret
endFound:
	mov rax, r14    ; 返回找到的索引
	pop r13
	pop r12
	pop rbx
	ret

你遗漏的关键概念盲区

  1. 平台调用约定的重要性:不同平台的参数传递规则完全不同,x86-64不是把参数压栈(那是32位x86的老规则),而是用寄存器传递前几个参数,这是最容易踩坑的点。
  2. 控制流的正确性:jmp指令会直接跳过后续代码,一定要确保初始化逻辑在进入循环前执行。
  3. 数组访问的细节:要区分「数组指针+偏移量」(元素地址)、「元素值」、「索引」这三个概念,x86里访问数组元素需要用[base + scale*index]的形式加载值,而索引是用来计算偏移的计数器。
  4. 32位/64位的兼容:因为你处理的是int(32位),所以用32位寄存器后缀(比如r10d、r13d)更准确,避免64位寄存器高位的垃圾值干扰比较。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 18:52:37