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

NASM x86汇编代码无法输出排序后字母序列,请求排查

问题排查:NASM x86汇编程序无法输出按出现次数降序的字母序列

预期输出

以下是程序应输出的内容
输入一段任意语言的字符串: "How much wood would a woodchuck chuck if a woodchuck could chuck wood?"
a:2 b:0 c:10 d:6 e:0 f:1 g:0 h:6 i:1 j:0 k:4 l:2 m:1 n:0 o:11 p:0 q:0 r:0 s:0 t:0 u:7 v:0 w:6 x:0 y:0 z:0
ocuwhdklamifzyxvtsrqpnjgeb

实际输出

输入一段任意语言的字符串: "How much wood would a woodchuck chuck if a woodchuck could chuck wood?"
a:2 b:0 c:10 d:6 e:0 f:1 g:0 h:6 i:1 j:0 k:4 l:2 m:1 n:0 o:11 p:0 q:0 r:0 s:0 t:0 u:7 v:0 w:6 x:0 y:0 z:0

原始NASM代码

%include "asm_io.inc"

section .data
    msg     db      "Enter a string written in some language: ", 0

section .bss
    counters resd    26 ; an array of 26 counters, each storing a 4-byte value
    sorted   resd    26 ; an array of 26 letters, sorted by decreasing number of occurrences
    input    resd   1   ; to store the input character

section .text
    global asm_main

asm_main:
    ; setup
    enter   0, 0
    pusha

    ; print prompt
    mov eax, msg
    call print_string

    ; loop to count characters
    mov ebx, counters
loop:
    call read_char ; read input character
    cmp  eax, 10 ; check if end of input (newline character)
    je end ; if newline character, exit loop
    cmp eax, 97 ; check if lowercase
    jl upper_case ; if less than 97, ignore
    cmp eax, 122 ; check if lowercase
    jg not_alpha ; if greater than 122, check uppercase
    sub eax, 97 ; ASCII value subtract by 97 to get index
    jmp update_counter

lowercase_counter:
    cmp eax, 0
    je next
    add ebx, 4
    dec eax
    jmp lowercase_counter

upper_case:
    cmp eax, 65 ; check if uppercase
    jl not_alpha ;if less than 65, ignore it
    cmp eax, 90 ; check if uppercase
    jg not_alpha ; if greater than 90, ignore it
    sub eax, 65 ; ASCII value subtract by 65 to get index
    jmp update_counter

uppercase_counter:
    cmp eax, 0
    je next
    add ebx, 4
    dec eax
    jmp uppercase_counter

not_alpha:
    ; ignore non-letter characters
    jmp loop

update_counter:
    inc dword [ebx+eax*4]
    mov ebx, counters
    jmp loop

next:
    mov ebx, counters
    jmp loop

end:
    ; print character counts
    mov ebx, counters
    mov ecx, 97
loop2:
    cmp ecx, 122
    jg end2
    mov eax, ecx
    call print_char
    mov eax, 58
    call print_char ; print the colon character
    mov eax, [ebx]
    call print_int
    mov eax, 32
    call print_char
    inc ecx
    add ebx, 4
    jmp loop2

 ; sort letters by decreasing count
    mov eax, sorted
    mov ebx, counters
    mov ecx, 26

outer_loop:
    mov edx, [ebx]
    mov [eax], edx
    add eax, 4
    add ebx, 4
    loop outer_loop

    mov eax, sorted
    mov ebx, 24

sort_loop:
    mov ecx, 0

inner_loop:
    mov edx, [eax]      ; move the value of the first element of the array into edx
    mov ebx, [eax + 4]  ; move the value ofthe second element of the array into ebx
    cmp edx, ebx ; compare the two values
    jge skip_swap ; if the first value is greater than or equal to the second value, skip the swap
    mov [eax], ebx ; move the second value to the first element of the array
    mov [eax + 4], edx ; move the first value to the second element of the array

skip_swap:
    add eax, 4 ; move to the next pair of elements in the array
    loop inner_loop ; repeat until all pairs have been compared and swapped (if necessary)
    dec ebx             ; move to the next element in the array, excluding the last element since it is already sorted
    cmp ebx, 0          ; check if we have reached the beginning of the array
    jge sort_loop       ; if not, repeat the sorting process for the remaining unsorted elements

   ; print sorted letters and their counts
    call print_nl
    mov eax, sorted
    mov ebx, counters
    mov ecx, 26

print_sorted:
    cmp ecx, 0
    jle end2
    mov edx, [eax]
    add eax, 4
    sub ecx, 1
    cmp edx, 0
    je print_sorted   ; skip printing if the count is 0
    add edx, 97
    mov eax, edx
    call print_char
    mov ebx, 58      ; store the ASCII code for ":" in ebx
    call print_char  ; print ":"
    mov eax, [ebx + (edx - 97) * 4] ; retrieve the count using the letter's ASCII value
    call print_int
    call print_nl
    jmp print_sorted

    

end2:
    call print_nl
    popa ; clean up
    mov eax, 0 ; clean up
    leave ; clean up
    ret ; clean up

问题根源

  1. 执行顺序错误:loop2的结束条件jg end2直接跳转到程序收尾的end2,导致排序和打印排序结果的代码完全未执行,这是最直接的原因。
  2. 排序逻辑设计错误:sorted数组仅存储计数,未关联对应字母索引,排序后无法映射回原字母。应存储0-25的索引,再根据counters的数值排序这些索引。
  3. 寄存器冲突:sort_loop中用ebx记录未排序元素数量,但inner_loop又用ebx存储数组元素值,导致寄存器被覆盖,排序逻辑混乱。
  4. 打印逻辑错误:打印排序结果时,错误地将sorted里的计数当作字母索引,还覆盖了指向counters的ebx,无法正确获取计数。

修复后的代码

%include "asm_io.inc"

section .data
    msg     db      "Enter a string written in some language: ", 0

section .bss
    counters resd    26 ; 存储a-z的出现次数,每个4字节
    sorted   resd    26 ; 存储排序后的字母索引(0-25),按出现次数降序
    input    resd    1   ; 存储输入字符

section .text
    global asm_main

asm_main:
    enter   0, 0
    pusha

    ; 打印提示信息
    mov eax, msg
    call print_string

    ; 统计字符出现次数
    mov ebx, counters
count_loop:
    call read_char
    cmp eax, 10        ; 检测换行符,结束输入
    je count_done
    cmp eax, 97        ; 小写字母a-z
    jl check_upper
    cmp eax, 122
    jg skip_char
    sub eax, 97        ; 转换为0-25的索引
    inc dword [ebx + eax*4]
    jmp count_loop

check_upper:
    cmp eax, 65        ; 大写字母A-Z
    jl skip_char
    cmp eax, 90
    jg skip_char
    sub eax, 65        ; 转换为0-25的索引
    inc dword [ebx + eax*4]
    jmp count_loop

skip_char:
    jmp count_loop

count_done:
    ; 打印原始计数结果
    mov ebx, counters
    mov ecx, 97        ; 从小写a开始
print_counts:
    cmp ecx, 122       ; 到z结束
    jg start_sort
    mov eax, ecx
    call print_char
    mov eax, 58        ; 冒号
    call print_char
    mov eax, [ebx]
    call print_int
    mov eax, 32        ; 空格
    call print_char
    inc ecx
    add ebx, 4
    jmp print_counts

start_sort:
    ; 初始化sorted数组为0-25的索引
    mov eax, sorted
    mov ecx, 26
    mov edx, 0
init_sorted:
    mov [eax], edx
    add eax, 4
    inc edx
    loop init_sorted

    ; 冒泡排序:按counters中的值降序排列sorted数组的索引
    mov ecx, 25        ; 外层循环次数:n-1次
outer_sort:
    mov esi, sorted
    mov ebx, 0         ; 内层循环计数器
inner_sort:
    mov edx, [esi]     ; 当前索引
    mov eax, [esi+4]   ; 下一个索引
    ; 比较两个索引对应的计数
    cmp dword [counters + edx*4], dword [counters + eax*4]
    jge no_swap        ; 当前计数 >= 下一个,不交换
    ; 交换两个索引
    mov [esi], eax
    mov [esi+4], edx
no_swap:
    add esi, 4
    inc ebx
    cmp ebx, ecx       ; 内层循环次数:n-1-外层循环次数
    jl inner_sort
    dec ecx
    jnz outer_sort

    ; 打印排序后的字母序列(不包含计数为0的)
    call print_nl
    mov esi, sorted
    mov ecx, 26
print_sorted:
    mov edx, [esi]
    add esi, 4
    dec ecx
    cmp dword [counters + edx*4], 0
    je print_sorted    ; 计数为0跳过
    mov eax, edx
    add eax, 97        ; 转换为小写字母ASCII
    call print_char
    jmp print_sorted

end_program:
    call print_nl
    popa
    mov eax, 0
    leave
    ret

修复说明

  1. 调整执行顺序:将loop2的结束跳转从end2改为start_sort,确保排序和打印代码能正常执行。
  2. 重构排序逻辑:sorted数组存储字母索引(0-25),排序时比较索引对应的counters值,实现按次数降序排列。
  3. 避免寄存器冲突:明确划分esi、ebx等寄存器的用途,不再重复使用同一寄存器存储不同含义的数据。
  4. 修正打印逻辑:根据sorted里的索引从counters获取对应计数,转换为字母后打印,匹配预期输出格式。

内容的提问来源于stack exchange,提问作者Kimchee

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 03:47:20