32位NASM凯撒密码程序异常:文件处理与字符移位问题
问题分析与修复
你的32位NASM凯撒密码程序存在多个关键错误,导致文件操作和移位逻辑失效,以下是具体问题和修复方案:
1. 系统调用参数传递错误(核心问题)
Linux 32位系统调用(int 0x80)的参数是通过固定寄存器顺序传递的:eax存系统调用号,参数依次放在ebx、ecx、edx、esi、edi、ebp中。你的代码错误地使用edi/esi传递sys_open参数,导致文件无法正确打开:
错误代码(打开输入文件):
mov eax, 5 ; sys_open mov edi, ebx ; input_file mov esi, 0 ; O_RDONLY int 0x80
正确写法:
mov eax, 5 ; sys_open mov ebx, input_file_ptr ; 文件名指针放入ebx mov ecx, 0 ; O_RDONLY 放入ecx int 0x80
同理,打开输出文件时,你不仅参数寄存器用错,标志值也有误:正确的O_WRONLY | O_CREAT | O_TRUNC是十进制577(十六进制0x241),而非你写的578。正确调用如下:
mov eax, 5 ; sys_open mov ebx, output_file_ptr ; 文件名指针 mov ecx, 0x241 ; O_WRONLY | O_CREAT | O_TRUNC mov edx, 0666 ; 文件权限放入edx int 0x80
2. 文件描述符管理错误
你直接用寄存器存储文件描述符,但寄存器会被后续操作覆盖,导致读写、关闭文件时使用错误的fd:
sys_write操作中mov ebx, ecx会覆盖输入fd的存储close_files中mov ebx, ebx此时ebx已经是输出fd,导致关闭错误的文件
修复方案:在.bss段定义变量存储输入/输出fd:
section .bss fd_in resd 1 fd_out resd 1 ; 其他变量...
打开文件后将fd存入这些变量:
; 打开输入文件后 mov dword [fd_in], eax ; 打开输出文件后 mov dword [fd_out], eax
后续读写/关闭时直接从变量中读取:
; 读文件 mov eax, 3 mov ebx, dword [fd_in] ; ... ; 写文件 mov eax, 4 mov ebx, dword [fd_out] ; ... ; 关闭文件 mov eax, 6 mov ebx, dword [fd_in] int 0x80 mov eax, 6 mov ebx, dword [fd_out] int 0x80
3. 凯撒移位逻辑完全错误
你的代码使用div bl实现循环移位,完全不符合凯撒密码的逻辑(凯撒密码是字符值+移位量后模26),而且代码中完全没有用到读取的shift值!
错误逻辑:
sub al, 'A' mov ebx, 26 div bl ; 除法操作,al得到商,与移位无关 add al, 'A'
正确的凯撒移位逻辑(大写字母):
sub al, 'A' ; 转换为0-25的范围 add al, dl ; 加上移位量dl(假设shift存在dl中) mov ah, 0 mov bl, 26 div bl ; ah是余数,即循环后的位置 mov al, ah add al, 'A'
同时要确保shift先被处理为0-25的范围,避免移位量过大。另外你当前的shift解析仅支持单个数字,如需多位数需扩展字符串转数字的逻辑。
修正后的完整代码
section .data usage db "Usage: ./caesar {input_file} {output_file} {shift}", 10, 0 len_usage equ $ - usage error_open_in db "Error: Cannot open input file.", 10, 0 len_error_open_in equ $ - error_open_in error_open_out db "Error: Cannot open output file.", 10, 0 len_error_open_out equ $ - error_open_out section .bss fd_in resd 1 fd_out resd 1 bytes_read resd 1 buffer resb 1024 buffer_size equ 1024 section .text global _start _start: ; 检查参数数量 mov eax, dword [esp+4] cmp eax, 4 je process_args ; 打印用法 mov eax, 4 mov ebx, 1 mov ecx, usage mov edx, len_usage int 0x80 jmp exit process_args: ; 获取参数指针 mov ebx, dword [esp+8] ; input_file mov ecx, dword [esp+12] ; output_file mov edx, dword [esp+16] ; shift字符串 ; 打开输入文件(O_RDONLY) mov eax, 5 mov ecx, 0 int 0x80 cmp eax, 0 jl error_open_input mov dword [fd_in], eax ; 打开输出文件(O_WRONLY | O_CREAT | O_TRUNC,权限0666) mov eax, 5 mov ebx, ecx ; 输出文件名指针 mov ecx, 0x241 ; 0x200(O_CREAT)|0x1(O_WRONLY)|0x40(O_TRUNC) mov edx, 0666 int 0x80 cmp eax, 0 jl error_open_output mov dword [fd_out], eax ; 解析shift为数字(仅支持单个数字,如需多位数需扩展) mov al, byte [edx] sub al, '0' mov dl, al ; shift存在dl中 ; 确保shift在0-25范围 cmp dl, 26 jb shift_ok sub dl, 26 shift_ok: read_loop: ; 读取输入文件 mov eax, 3 mov ebx, dword [fd_in] mov ecx, buffer mov edx, buffer_size int 0x80 cmp eax, 0 jle close_files mov dword [bytes_read], eax ; 处理每个字符 mov esi, buffer mov ecx, dword [bytes_read] process_char: mov al, byte [esi] ; 检查大写字母 cmp al, 'A' jb skip_char cmp al, 'Z' ja check_lower ; 大写处理 sub al, 'A' add al, dl mov ah, 0 mov bl, 26 div bl mov al, ah add al, 'A' jmp store_char check_lower: ; 检查小写字母 cmp al, 'a' jb skip_char cmp al, 'z' ja skip_char ; 小写处理 sub al, 'a' add al, dl mov ah, 0 mov bl, 26 div bl mov al, ah add al, 'a' store_char: mov byte [esi], al skip_char: inc esi loop process_char ; 写入输出文件 mov eax, 4 mov ebx, dword [fd_out] mov ecx, buffer mov edx, dword [bytes_read] int 0x80 jmp read_loop close_files: ; 关闭输入文件 mov eax, 6 mov ebx, dword [fd_in] int 0x80 ; 关闭输出文件 mov eax, 6 mov ebx, dword [fd_out] int 0x80 exit: mov eax, 1 xor ebx, ebx int 0x80 error_open_input: mov eax, 4 mov ebx, 1 mov ecx, error_open_in mov edx, len_error_open_in int 0x80 jmp exit error_open_output: mov eax, 4 mov ebx, 1 mov ecx, error_open_out mov edx, len_error_open_out int 0x80 jmp exit
内容的提问来源于stack exchange,提问作者MiniX D
相关产品推荐
相关产品推荐

