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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 14:49:52