gpt4 book ai didi

assembly - 无法在 Linux NASM 中打印单个字符

转载 作者:行者123 更新时间:2023-12-05 04:00:28 26 4
gpt4 key购买 nike

我尝试制作一个程序,它接受一些输入,找到字符串中的奇数位置并打印相应的字符,所以你输入“somewords”并打印“oeod”。
我最终制作了一个遍历字符串的循环,然后将计数器除以 2,如果余数不等于 0,则打印计数器位置的字符。

它不打印任何字符,而不是单个字符。

完整代码:

SECTION .bss
inp: resb 255

SECTION .data
msg db "Enter the string: ", 0h

SECTION .text
global _start

_start:
mov eax, msg
call stprint

mov edx, 255 ; take user input
mov ecx, inp
mov ebx, 0
mov eax, 3
int 80h

call findodd

mov ebx, 0
mov eax, 1
int 80h

findodd:
push eax
push ecx
push edx
push esi
push ebx

mov ecx, 0 ; counter
mov esi, 2 ; divider

.iterstring:
mov eax, inp ; move input to eax
cmp byte [eax+ecx], 0 ; check for end of the string in position
je .finish ; if equal, finish
inc ecx

push eax
mov eax, ecx ; move counter to eax
xor edx, edx ; divide it by 2
idiv esi
pop eax
cmp edx, 0 ; check the remainder
jnz .printchar ; print character if != 0
jmp .iterstring

.printchar:
push eax
push ebx
movzx ebx, byte [eax+ecx] ; move single byte to ebx

push ecx
mov ecx, ebx ; move ebx to print
mov edx, 1 ; print the character
mov ebx, 1
mov eax, 4
int 80h

pop ecx
pop eax
pop ebx
jmp .iterstring

.finish:
pop eax
pop ecx
pop edx
pop esi
pop ebx
ret

; print string function (taken from tutorial)
; if I try to print single character with it I get SEGFAULT
stprint:
push edx
push ecx
push ebx
push eax
call stlen

mov edx, eax
pop eax

mov ecx, eax
mov ebx, 1
mov eax, 4
int 80h

pop ebx
pop ecx
pop edx
ret

stlen:
push ebx
mov ebx, eax

nextch:
cmp byte [eax], 0
jz finish
inc eax
jmp nextch

finish:
sub eax, ebx
pop ebx
ret

我尝试使用 bl、al 和 cl,但没有成功。我也试着做了一些检查。例如,在 .iterstring 中打印计数器:

nasm -f elf lr3.asm && ld -m elf_i386 lr3.o -o lr3 && ./lr3
Enter the string: test
1
2
3
4
5

所以看起来迭代工作正常。

我最幸运的是回答了类似的问题 ( How to print a character in Linux x86 NASM? ) 对代码进行了这样的更改:

.printchar:
push eax
push ebx
push esi
mov eax, inp
movzx ebx, byte [eax+ecx]
mov esi, ecx ; see below

push ecx
push ebx
mov ecx, esp
mov edx, 1 ; print the character
mov ebx, 1
mov eax, 4
int 80h

pop ecx
pop ebx
pop eax
pop ebx
mov ecx, esi ; without this it just prints 1 character and ends
pop esi ; so ecx is not restored with pop for some reason?
jmp .iterstring

但它会打印除第一个字符以外的所有内容:

nasm -f elf lr3.asm && ld -m elf_i386 lr3.o -o lr3 && ./lr3
Enter the string: somewords
mewords

我卡住了,不知道我的错误是什么。

编辑,最终代码:

findodd:
push eax
push ecx
push edx
push esi
push ebx
mov esi, 0 ; counter
mov eax, inp

.iterstring:
inc esi
cmp byte [eax+esi], 0
jz .finish
test esi,1
jz .iterstring

movzx ecx, byte [eax+esi]
push ecx
mov ecx, esp
mov edx, 1
mov ebx, 1
push eax
mov eax, 4
int 80h
pop eax
pop ecx
jmp .iterstring

.finish:
pop eax
pop ecx
pop edx
pop esi
pop ebx
ret

现在它按预期工作了:

nasm -f elf lr3.asm && ld -m elf_i386 lr3.o -o lr3 && ./lr3
Enter the string: somewords
oeod

我不得不删除更多的 push-pop 指令,并且还不得不将 counter 移到 esi 中,因为压入然后弹出寄存器并不总能恢复它们在堆栈中的值,这对我来说很奇怪。
当我试图移动到 byte [eax+ecx] 的 ecx 地址时,它起作用了,但是当我将它更改为 byte [eax+1] 时,它会出现段错误,因为恢复 eax流行之后会破裂。当我按下 ecx 打印出一条消息然后将其弹出时,它以段错误结束,并且 gdb 显示弹出后 ecx 中有垃圾代码。
使用当前代码,它可以正常工作。

最佳答案

此行不正确:

mov    ecx, ebx  ; move ebx to print

write (int 80h/eax=4) 期望 ecx 包含数据的地址写(见 this table )。但是您传递的是数据本身。

在您修改后的代码中,您将字符放在堆栈上,然后在 ecx 中传递它的地址,所以这是正确的。但是,当您到达 .printchar 时,您已经递增了 ecx。这就是为什么您的代码不打印第一个字符的原因。

附带说明一下,您对偶数/奇数的检查过于复杂。它可以简化为:

test ecx,1      ; set EFLAGS based on ecx AND 1
jnz .printchar

关于assembly - 无法在 Linux NASM 中打印单个字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56213267/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com