linux - x86 NASM | 循环输入仅在第一次和第三次工作
问题描述
我有一个成功运行 3 次的循环,但我在此循环中的输入仅在第一次有效。我是组装新手,所以请耐心等待。
代码:
section .bss
| d times 3 resb 1 ;array to store input
| i resb 1 ;counter
section .text
| global _start
|
| _start:
| | mov ecx, 3
| | mov [i], byte 0
| |
| | loop_here:
| | | push ecx
| | |
| | | mov eax, 3
| | | mov ebx, 0
| | | mov ecx, d
| | | add ecx, [i]
| | | inc byte [i]
| | | mov edx, 1
| | | int 80h
| | |
| | | pop ecx
| | loop loop_here
| |
| | mov eax, 1
| | xor ebx, ebx
| | int 80h
输出:
2 ;I inserted 2 as an input
2 ;I inserted 2 again as input
[Program finishes]
好吧,后来我认为循环可能不会运行第三次,所以我稍微更改了代码。
新代码:
section .bss
| d times 3 resb 1 ;array to store input
| i resb 1 ;counter
section .text
| global _start
|
| _start:
| | mov ecx, 3
| | mov [i], byte 0
| |
| | loop_here:
| | | push ecx
| | |
| | | mov eax, 4
| | | mov ebx, 1
| | | mov ecx, i
| | | add [ecx], byte 30h ;to actually print the count
| | | mov edx, 1
| | | int 80h
| | | sub [i], byte 30h ;to make again a counter
| | |
| | | mov eax, 3
| | | mov ebx, 0
| | | mov ecx, d
| | | add ecx, [i]
| | | inc byte [i]
| | | mov edx, 1
| | | int 80h
| | |
| | | pop ecx
| | loop loop_here
| |
| | mov eax, 1
| | xor ebx, ebx
| | int 80h
新输出:
02
122
[Program finishes]
解释:
0 是计数器,2 是我的输入。1 和 2 是计数器,第二个 2 是我的第二个输入,这意味着循环运行成功,它只是在第二次运行时忽略了输入代码
另外,我在代码中使用直线来可视化范围是否使我的代码更具可读性?
解决方案
彼得已经在评论中很好地涵盖了大部分内容,但我想我会更详细地介绍:
x86loop
指令假定您在ecx
. 如果不是0loop
,则自动递减ecx
并跳转到循环标签。由于您在循环中调用 linux 系统调用,并且 linux 期望缓冲区指针位于,您可能应该使用不同的寄存器作为循环计数器和某种跳转改为执行此操作的说明:ecx
ecx
mov esi, 3 ; esi is your loop counter - loop 3 times
loop_here:
; do syscall
dec esi ; decrement loop counter
jnz loop_here ; jump to loop_here if esi is not zero
但是,在循环中调用系统调用并不是很有效。相反,您可以执行以下操作:
mov eax, 3 ; read
mov ebx, 0 ; fd for stdin
mov ecx, d ; address of d buffer into ecx
mov edx, 3 ; read 3 characters at most, the size of your buffer
int 80h
mov esi, eax ; read returns the number of bytes read in eax.
; we'll save it in esi
xor edi, edi ; edi will be our loop counter, this makes it 0
loop_here: ; first, we'll print the loop counter value
mov eax, 4 ; write
mov ebx, 1 ; fd for stdout
mov ecx, i ; address of i for write
mov edx, 1 ; write 1 byte
add edi, '0' ; convert edi loop counter to ASCII
mov [i], byte edi ; put lower byte of edi in i
int 80h
sub edi, '0' ; restore edi
mov eax, 4
mov ebx, 1
mov ecx, d ; address of d for write,
add ecx, edi ; plus current loop counter (offset)
mov edx, 1
int 80h
inc edi ; increment loop counter
cmp esi, edi ; compare to number of bytes read
jne loop_here ; jump to loop_here if not equal
这会调用一次读取,但仍会在循环中调用write来写入计数器和 的值d
。
要跳过输入中的尾随换行符,您可以在调用read之后尝试执行此操作(记住eax
读取的字节数):
movzx edi, byte [d+eax-1] ; move and zero-extend last byte of d into edi
cmp edi, `\n` ; is it a newline? (backticks required)
jne skip ; skip if not
dec eax ; otherwise, we'll print one less byte
skip:
; rest of your code here
换行符仍将存储在内存中,但您不会打印它,因为您将少循环一次。
推荐阅读
- json - Excel 文件下载导出到 React JS 中的 excel 并保留格式。下拉应保留在 xlsl 文件中
- drake - 如何使用 autoDiffToGradientMatrix 求解德雷克中的科里奥利矩阵?
- python - 如何在执行 10 倍交叉验证时在每次拆分时获得 Lasso Regression 中的系数?
- python - “康达删除
" 永远移除包裹 - powershell - windows 7 powershell v2.0创建共享文件夹后如何给不同用户共享权限
- python - Python回合 - 两个决定性的小数
- flutter - Flutter 使用 PageController 从另一个类更改 PageView
- xamarin.forms - Xamarin Forms iOS 构建失败,缺少图像
- charts - Oracle 顶点图表中的分层系列
- reactjs - 未找到 Zoom Web SDK 模块