如何修复汇编代码中反转5字符字符串时出现的段错误?
ARM汇编字符串反转问题:原串输出+段错误修复
尝试编写ARM汇编代码反转用户输入的5字符字符串,结果程序不仅只打印原字符串,还触发segmentation error(段错误)。原代码如下:
.data // start of the data segment input: .space 100 inputSize = .-input prompt: .asciz "Enter a string with 5 characters" promptSize = .-prompt reversed: .space 100 reversedSize = .-reversed .text // start o the text segment (Code) .global _start // Linux Standard _start, similar to main in C/C++ _start: // Display prompt message mov x0, #0 // stdout ldr x1, =prompt // store the address of flow into x1 ldr x2, =promptSize // store the size of the flowwWorld string into x2 mov x8, #64 // store 64 to x8, this is the linux write call svc 0 mov x0, #1 // file descriptor for stdin ldr x1, =input // store the address of flow into x1 ldr x2, =inputSize mov x8, #63 // system call number for read svc 0 mov x0, #1 // file descriptor for stdout ldr x1, =input // address of input buffer mov x2, #100 // maximum number of bytes to write mov x8, #64 // system call number for write svc 0 // Reverse the input string mov x1, #0 // set x1 to 0 to represent the start of the input string add x2, x2, #-2 // set x2 to the second-to-last index in the input string mov x4, #0 loop: cmp x4, #2 b.gt end ldrb w3, [x1], #1 // load byte from input string starting from the left ldrb w4, [x2], #-1 // load byte from input string starting from the right strb w4, [x1, #-1] // store right byte at the left index strb w3, [x2, #1] // store left byte at the right index add x4, x4, 1 b loop // jump to loop end: // Display the reversed string mov x0, #0 // stdout ldr x1, =input // store the address of input into x1 ldr x2, =inputSize // store the size of the input string into x2 mov x8, #64 // store 64 to x8, this is the linux write call svc 0 // Exit to the OS, essentially this code does this in c // return 0; mov x0, #0 // return value mov x8, #93 // Service call code svc 0
错误原因拆解
原代码的核心问题集中在输入输出逻辑、指针初始化和寄存器冲突上:
- 文件描述符搞反:stdout的文件描述符是1,原代码把提示输出写到了stdin(
x0=#0);读取输入时又用了stdout(x0=#1),导致输入根本没被正确读到缓冲区里。 - 指针指向非法内存:反转逻辑里把x1设为0,直接访问内存地址0,必然触发段错误;而且x2被之前的
mov x2, #100覆盖,根本不是输入字符串的实际长度,索引计算完全错误。 - 寄存器被非法覆盖:循环计数器x4被用来存储读取的右字节,导致循环条件判断混乱,循环逻辑失效。
- 输出参数错误:反转后的字符串输出时,又把x0设成了stdin,而且用了100的固定长度,输出内容完全不对。
修正后的代码
.data // 数据段开始 input: .space 100 inputSize = .-input prompt: .asciz "Enter a string with 5 characters\n" promptSize = .-prompt reversed: .space 100 reversedSize = .-reversed .text // 代码段开始 .global _start // Linux标准入口,类似C/C++的main _start: // 显示提示信息 mov x0, #1 // stdout文件描述符为1 ldr x1, =prompt // 加载提示字符串地址 ldr x2, =promptSize // 加载提示字符串长度 mov x8, #64 // Linux write系统调用号 svc 0 // 读取用户输入并保存字节数 mov x0, #0 // stdin文件描述符为0 ldr x1, =input // 加载input缓冲区地址 ldr x2, =inputSize // 最大读取字节数 mov x8, #63 // Linux read系统调用号 svc 0 mov x5, x0 // 把读取到的字节数存到x5,避免被覆盖 // 打印原输入(用于对比) mov x0, #1 // stdout ldr x1, =input // input缓冲区地址 mov x2, x5 // 实际读取的字节数 mov x8, #64 // write系统调用 svc 0 // 反转字符串逻辑 ldr x1, =input // x1指向input起始地址 sub x2, x1, #1 // 计算最后一个有效字符地址:起始地址-1 + 读取字节数 add x2, x2, x5 mov x4, #0 // 循环计数器,5字符需要交换2次(0<->4,1<->3) loop: cmp x4, #2 b.gt end_loop // 计数器大于2时退出循环 ldrb w3, [x1] // 读取左指针位置的字节 ldrb w6, [x2] // 读取右指针位置的字节(用w6避免覆盖计数器x4) strb w6, [x1] // 把右字节写入左指针位置 strb w3, [x2] // 把左字节写入右指针位置 add x1, x1, #1 // 左指针右移一位 sub x2, x2, #1 // 右指针左移一位 add x4, x4, #1 // 计数器加1 b loop end_loop: // 打印反转后的字符串 mov x0, #1 // stdout ldr x1, =input // 反转后的input缓冲区地址 mov x2, x5 // 实际读取的字节数 mov x8, #64 // write系统调用 svc 0 // 退出程序 mov x0, #0 // 返回值0 mov x8, #93 // exit系统调用号 svc 0
关键修改点
- 修正了文件描述符,确保输入输出方向正确;
- 保存读取的字节数到x5,保证索引计算基于实际输入长度;
- 让x1指向input缓冲区的真实地址,避免访问非法内存;
- 用独立寄存器存储右字节,不再覆盖循环计数器;
- 手动移动指针,逻辑更清晰,避免自动寻址带来的错误;
- 输出时使用实际读取长度,避免输出多余空字符。
内容的提问来源于stack exchange,提问作者kate
相关产品推荐
相关产品推荐

