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
问题根源
- 执行顺序错误:
loop2的结束条件jg end2直接跳转到程序收尾的end2,导致排序和打印排序结果的代码完全未执行,这是最直接的原因。 - 排序逻辑设计错误:
sorted数组仅存储计数,未关联对应字母索引,排序后无法映射回原字母。应存储0-25的索引,再根据counters的数值排序这些索引。 - 寄存器冲突:
sort_loop中用ebx记录未排序元素数量,但inner_loop又用ebx存储数组元素值,导致寄存器被覆盖,排序逻辑混乱。 - 打印逻辑错误:打印排序结果时,错误地将
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
修复说明
- 调整执行顺序:将
loop2的结束跳转从end2改为start_sort,确保排序和打印代码能正常执行。 - 重构排序逻辑:
sorted数组存储字母索引(0-25),排序时比较索引对应的counters值,实现按次数降序排列。 - 避免寄存器冲突:明确划分
esi、ebx等寄存器的用途,不再重复使用同一寄存器存储不同含义的数据。 - 修正打印逻辑:根据
sorted里的索引从counters获取对应计数,转换为字母后打印,匹配预期输出格式。
内容的提问来源于stack exchange,提问作者Kimchee
相关产品推荐
相关产品推荐

