x86 GAS汇编调用异常排查:为何执行asm_function出现段错误?
调用汇编函数出现段错误且无返回值的原因及修复
一、C代码里的致命错误
- 内存分配错误:
create_array里用malloc(sizeof(array)),array是指针类型,32位系统下只会分配4字节,64位是8字节,但你要存size=10个int,应该改成malloc(sizeof(int) * size),否则数组越界直接触发内存访问错误。 - 循环初始化与范围问题:循环从
i=1开始,array[0]未初始化;且循环条件i < size,当size=10时,会给array[1]到array[9]赋值,但原分配的空间根本不够,进一步加剧越界问题。
二、汇编代码里的核心错误
- 参数顺序完全搞反:C的cdecl调用约定中,参数是从右往左压栈,所以
asm_function(index, size, data)的栈布局是:8(%ebp)→ 第一个参数index12(%ebp)→ 第二个参数size16(%ebp)→ 第三个参数data
但你汇编里把8(%ebp)当成data、16(%ebp)当成index,直接导致访问了错误的内存地址,这是段错误的直接原因。
- 无效的内存访问:
movl (%ecx, %edi, 4), %edx这行,因为参数拿反了,实际是用index作为基址、size作为索引计算地址,完全不是你要访问的data[index],必然触发非法内存访问。 - 返回值逻辑混乱:循环里
movl %esi, %eax只是把循环变量i赋值给返回寄存器,但这和你调用函数想要获取的data[index]逻辑无关,最后返回的是循环结束后的i值,完全不符合预期。
三、修正后的代码
修正后的C代码
#include <stdio.h> #include <stdlib.h> extern int asm_function(int index, int size, int* data); int *create_array(int size){ // 分配足够的内存并初始化所有元素为0 int *array = calloc(size, sizeof(int)); for(int i = 0; i < size; i++){ array[i] = i; } return array; } int main(int argc, char **argv) { int index = 5; int size = 10; int *data = create_array(size); int value = asm_function(index, size, data); printf("Value %d\n", value); // 释放内存避免泄漏 free(data); return 0; }
修正后的汇编代码(32位x86,cdecl约定)
FUNC(asm_function): pushl %ebp movl %esp, %ebp // 保存非易失性寄存器 pushl %ebx pushl %esi pushl %edi // 正确读取参数:index(8), size(12), data(16) movl 8(%ebp), %ecx ; ecx = index movl 16(%ebp), %ebx ; ebx = data ; 计算 data[index] = *(ebx + ecx*4),存入eax作为返回值 movl (%ebx, %ecx, 4), %eax // 保留原循环逻辑(若需要遍历数组),已修正参数引用 movl $1, %esi ; i = 1 loops: cmpl 12(%ebp), %esi ; 比较i和size jge exit ; i >= size则退出循环 movl %esi, (%ebx, %esi, 4) ; array[i] = i incl %esi jmp loops exit: // 恢复寄存器 popl %edi popl %esi popl %ebx popl %ebp ret
四、关键说明
修正后汇编首先正确读取了参数,把data[index]加载到eax(x86下返回值存在eax寄存器),同时C代码修复了内存分配和循环问题,运行后会正确返回data[5]的值5(若保留循环,数组元素会被重新赋值,但返回值仍为初始设定的data[5])。
内容的提问来源于stack exchange,提问作者markuslw
相关产品推荐
相关产品推荐

