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



我尝试制作一个程序,以获取一些输入,在字符串中找到奇数位置并打印相应的字符,因此您输入'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

因此,迭代似乎可以正常工作。

我在答案中获得的最幸运的问题(如何在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

我必须删除更多的推送说明,并且还必须将计数器转入ESI,因为推动然后弹出寄存器并不总是在堆栈中恢复其价值,这对我来说很奇怪。
当我尝试进入byte [eax+ecx]的ECX地址时,它有效,但是当我将其更改为byte [eax+1]时,它将segfault segfault,因为在POP后恢复EAX会破裂。当我推动ECX打印一条消息然后弹出消息时,它最终以Segfault和GDB结束,并且GDB表明ECX弹出后内部有垃圾代码。

使用当前代码,它可以正常工作。

此行不正确:

mov    ecx, ebx  ; move ebx to print

write(int 80h / eax=4(期望ecx包含编写数据的地址(请参阅此表(。但是您正在传递数据本身。

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

作为旁注,您对偶数/奇数数字的支票无关紧要。它可以简化为:

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

最新更新