NASM汇编向C函数传递字符串指针数组时遇段错误求助
问题描述
我是汇编新手,正在完成课程任务:通过NASM汇编代码向C函数传递字符串指针数组,调用display函数打印数组中的字符串(validate函数可忽略)。在WSL环境下运行代码,GDB调试时能看到字符串输出,但程序触发SIGSEGV段错误。怀疑是指针传递或内存操作有误,以下是相关信息:
报错信息
Program received signal SIGSEGV, Segmentation fault. 0x00007ffff7e32540 in _int_malloc (av=av@entry=0x7ffff7fa7c80 <main_arena>, bytes=bytes@entry=640) at ./malloc/malloc.c:4375 4375 ./malloc/malloc.c: No such file or directory. (gdb) where #0 0x00007ffff7e32540 in _int_malloc (av=av@entry=0x7ffff7fa7c80 <main_arena>, bytes=bytes@entry=640) at ./malloc/malloc.c:4375 #1 0x00007ffff7e32a49 in tcache_init () at ./malloc/malloc.c:3245 #2 0x00007ffff7e3325e in tcache_init () at ./malloc/malloc.c:3241 #3 __GI___libc_malloc (bytes=bytes@entry=1024) at ./malloc/malloc.c:3306 #4 0x00007ffff7e0cc24 in __GI__IO_file_doallocate (fp=0x7ffff7fa8780 <_IO_2_1_stdout_>) at ./libio/filedoalloc.c:101 #5 0x00007ffff7e1bd60 in __GI__IO_doallocbuf (fp=fp@entry=0x7ffff7fa8780 <_IO_2_1_stdout_>) at ./libio/libioP.h:947 #6 0x00007ffff7e1afe0 in _IO_new_file_overflow (f=0x7ffff7fa8780 <_IO_2_1_stdout_>, ch=-1) at ./libio/fileops.c:744 #7 0x00007ffff7e19755 in _IO_new_file_xsputn (n=22, data=<optimized out>, f=<optimized out>) at ./libio/libioP.h:947 #8 _IO_new_file_xsputn (f=0x7ffff7fa8780 <_IO_2_1_stdout_>, data=<optimized out>, n=22) at ./libio/fileops.c:1196 #9 0x00007ffff7e0ef9c in __GI__IO_puts (str=0x404058 "This is the original.\n") at ./libio/libioP.h:947 #10 0x0000000000401307 in display () #11 0x00000000004011bb in loop () #12 0x00007ffff7db7d90 in __libc_start_call_main (main=main@entry=0x401180 <main>, argc=argc@entry=1, argv=argv@entry=0x7fffffffdf18) at ../sysdeps/nptl/libc_start_call_main.h:58 #13 0x00007ffff7db7e40 in __libc_start_main_impl (main=0x401180 <main>, argc=1, argv=0x7fffffffdf18, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdf08) at ../csu/libc-start.c:392 #14 0x00000000004010b5 in _start ()
原NASM代码
;Extern ceasar ;calling my project3 ;All funcitons below are writen in C ;Extern read_message ;read message from user Extern display ;display the strings ;Extern decrypt ;decypt function extern freeUp ;free memory extern printf extern validate extern fprintf section .data defaultMessage db "This is the original.", 10, 0 len_Mess equ $-defaultMessage fmtpf db "%d", 10, 0 section .bss array resq 10 section .text global main main: mov r8, 64 mov r9, 0 xor r10,r10 mov r11, 10 loop: mov qword[array + r10], defaultMessage add r10, r8 add r9, 1 cmp r9, r11 JLE loop mov rdi, array call display call validate mov [array], rax exit: mov rax, 60 mov rdi, [array] call freeUp xor rdi, rdi syscall
原C代码
#include <stdio.h> #include <stdlib.h> #include <string.h> char* validate(){ int buffer = 256; int pos = 0; char* cmd = malloc(sizeof(char) * buffer); int cha; int cont = 1; while(cont == 1){ cha = fgetc(stdin); if(cha == EOF || cha == '\n'){ cmd[pos] = '\0'; cont = 0; } else{ cmd[pos] = cha; } pos++; if(pos >= buffer){ buffer += 256; cmd = realloc(cmd, buffer); } } return cmd; } void display(char** Array){ for(int i = 0; i < 10; i++){ printf("%s\n", Array[i]); } return; } void freeUp(char* msg){ free(msg); }
需求:实现从汇编向C传递数组并打印所有字符串,排查并解决段错误问题。
错误原因分析
- 数组元素偏移量错误:x86_64架构下指针长度为8字节,但代码中用
mov r8, 64作为元素间隔,导致每次写入数组时跳过64字节,远超array resq 10(仅80字节)的范围,破坏了BSS段外的内存,干扰了libc内部内存管理结构,触发malloc时的段错误。 - 循环次数超出数组容量:设置
r11=10且用JLE loop作为循环条件,会导致循环执行11次(r9从0到10),但数组仅能容纳10个元素,进一步加剧内存越界。 - C代码printf格式问题:原代码中
printf("%s ", Array[i])是无效转义,需改为printf("%s\n", Array[i])避免输出异常。
修复后的代码
修正后的NASM代码
;Extern ceasar ;calling my project3 ;All funcitons below are writen in C ;Extern read_message ;read message from user Extern display ;display the strings ;Extern decrypt ;decypt function extern freeUp ;free memory extern printf extern validate extern fprintf section .data defaultMessage db "This is the original.", 10, 0 len_Mess equ $-defaultMessage fmtpf db "%d", 10, 0 section .bss array resq 10 ; 10个8字节指针,共80字节 section .text global main main: mov r8, 8 ; x86_64下指针为8字节,设置正确偏移量 mov r9, 0 xor r10, r10 mov r11, 10 loop: mov qword[array + r10], defaultMessage add r10, r8 add r9, 1 cmp r9, r11 JL loop ; 改为JL,循环10次(r9从0到9),避免越界 mov rdi, array call display ; 若不需要validate和freeUp逻辑,可暂时注释以确保核心功能正常 ; call validate ; mov [array], rax exit: ; 注意:defaultMessage在只读数据段,不能free;若要free validate返回的指针,需确保逻辑正确 ; mov rdi, [array] ; call freeUp mov rax, 60 xor rdi, rdi syscall
修正后的C代码(主要修正printf格式)
#include <stdio.h> #include <stdlib.h> #include <string.h> char* validate(){ int buffer = 256; int pos = 0; char* cmd = malloc(sizeof(char) * buffer); int cha; int cont = 1; while(cont == 1){ cha = fgetc(stdin); if(cha == EOF || cha == '\n'){ cmd[pos] = '\0'; cont = 0; } else{ cmd[pos] = cha; } pos++; if(pos >= buffer){ buffer += 256; cmd = realloc(cmd, buffer); } } return cmd; } void display(char** Array){ for(int i = 0; i < 10; i++){ printf("%s", Array[i]); // defaultMessage已包含换行符,无需额外添加\n;也可保持printf("%s\n", Array[i]) } return; } void freeUp(char* msg){ free(msg); }
验证方法
在WSL中执行以下命令编译运行:
nasm -f elf64 your_asm_file.asm -o asm.o gcc asm.o your_c_file.c -o program ./program
程序会正常打印10次This is the original.,且无段错误触发。
内容的提问来源于stack exchange,提问作者Jabril_hall
相关产品推荐
相关产品推荐

