Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 输入字符串并输出为大写_Linux_Assembly_Io_X86_Nasm - Fatal编程技术网

Linux 输入字符串并输出为大写

Linux 输入字符串并输出为大写,linux,assembly,io,x86,nasm,Linux,Assembly,Io,X86,Nasm,我正在尝试编写一个程序,将小写字符串转换为大写,使用缓冲区存储初始字符串。我遇到的问题是,我的程序将打印出一个无限循环的字符,这些字符必须与我给定的字符串相似 我认为守则中存在的其他问题如下: 有些子程序在调用结束时使用ret。我遇到的问题是,找出这些子例程中哪些实际上不需要ret,并且更好地与jmp一起使用。老实说,我对这两者的语义有点困惑。例如,使用ja调用的子例程是否需要在调用结束时进行ret 我还试图打印出用于转换值的循环的每个迭代中发生的迭代次数。不管出于什么原因,我将inc计数器,

我正在尝试编写一个程序,将小写字符串转换为大写,使用缓冲区存储初始字符串。我遇到的问题是,我的程序将打印出一个无限循环的字符,这些字符必须与我给定的字符串相似

我认为守则中存在的其他问题如下:

  • 有些子程序在调用结束时使用
    ret
    。我遇到的问题是,找出这些子例程中哪些实际上不需要
    ret
    ,并且更好地与
    jmp
    一起使用。老实说,我对这两者的语义有点困惑。例如,使用
    ja
    调用的子例程是否需要在调用结束时进行
    ret

  • 我还试图打印出用于转换值的循环的每个迭代中发生的迭代次数。不管出于什么原因,我将
    inc
    计数器,并决定使用
    PrintNumIter
    例程打印它,遗憾的是,它没有做任何事情

完整的程序如下

Codez

bits 32

[section .bss]

        buf: resb 1024                  ;allocate 1024 bytes of memory to buf

[section .data]

        ;*************
        ;* CONSTANTS *
        ;*************

        ;ASCII comparison/conversion

        LowercaseA:     equ 0x61
        LowercaseZ:     equ 0x7A
        SubToUppercase: equ 0x20

        ;IO specifiers/descriptors

        EOF:            equ 0x0

        sys_read:       equ 0x3
        sys_write:      equ 0x4

        stdin:          equ 0x0
        stdout:         equ 0x1
        stderr:         equ 0x2

        ;Kernel Commands/Program Directives

        _exit:          equ 0x1
        exit_success:   equ 0x0
        execute_cmd:    equ 0x80

        ;Memory Usage

        buflen:         equ 0x400   ;1KB of memory


        ;*****************
        ;* NON-CONSTANTS *
        ;*****************

        iteration_count:    db 0
        query :             db "Please enter a string of lowercase characters, and I will output them for you in uppercase ^.^: ", 10   
        querylen :          equ $-query

[section .text]

    global _start
;===========================================
;             Entry Point
;===========================================

_start:
        nop                                         ;keep GDB from complaining
        call    AskUser 
        call    Read
        call    SetupBuf
        call    Scan
        call    Write
        jmp     Exit

;===========================================
;           IO Instructions
;===========================================

Read:
        mov     eax, sys_read                       ;we're going to read in something
        mov     ebx, stdin                          ;where we obtain this is from stdin
        mov     ecx, buf                            ;read data into buf
        mov     edx, buflen                         ;amount of data to read

        int     execute_cmd                         ;invoke kernel to do its bidding
        ret

Write:
        mov     eax, sys_write                      ;we're going to write something
        mov     ebx, stdout                         ;where we output this is going to be in stdout
        mov     ecx, buf                            ;buf goes into ecx; thus, whatever is in ecx gets written out to
        mov     edx, buflen                         ;write the entire buf

        int     execute_cmd                         ;invoke kernel to do its bidding
        ret

AskUser:
        mov     eax, sys_write
        mov     ebx, stdout
        mov     ecx, query
        mov     edx, querylen   

        int     execute_cmd
        ret

PrintNumIter:
        mov     eax, sys_write
        mov     ebx, stdout
        push    ecx                                 ;save ecx's address
        mov     ecx, iteration_count                ;print the value of iteration_count
        mov     edx, 4                              ;print 4 bytes of data

        int     execute_cmd
        pop     ecx                                 ;grab the value back in
        ret
;===========================================
;           Program Preperation
;===========================================

SetupBuf:
        mov     ecx, esi                        ;place the number of bytes read into ecx
        mov     ebp, buf                        ;place the address of buf into ebp
        dec     ebp                             ;decrement buf by 1 to prevent "off by one" error
        ret                                         

;===========================================
;           Conversion Routines     
;===========================================

ToUpper:
        sub     dword [ebp + ecx], SubToLowercase   ;grab the address of buf and sub its value to create uppercase character


Scan:
        call    PrintNumIter                        ;print the current iteration within the loop

        cmp     dword [ebp + ecx], LowercaseA       ;Test input char against lowercase 'a'
        jb      ToUpper                             ;If below 'a' in ASCII, then is not lowercase - goto ToLower

        cmp     dword [ebp + ecx], LowercaseZ       ;Test input char against lowercase 'z'
        ja      ToUpper                             ;If above 'z' in ASCII, then is not lowercase - goto ToLower

        dec     ecx                                 ;decrement ecx by one, so we can get the next character
        inc     byte [iteration_count]              ;increment the __value__ in iteration count by 1
        jnz     Scan                                ;if ecx != 0, then continue the process
        ret

;===========================================

;Next:
;       dec     ecx                             ;decrement ecx by one
;       jnz     Scan                            ;if ecx != 0 scan
;       ret

;===========================================

Exit:
        mov     eax, _exit
        mov     ebx, exit_success

        int     execute_cmd

您的问题直接归因于这样一个事实:在处理完字符串缓冲区后,您从未将nul终止符追加到它的末尾(据我所知,
read
syscall不会读回null)

不幸的是,由于您的控制流很奇怪,这有点难做到,但是更改
SetupBuf
应该可以做到(注意,您可能应该检查您没有溢出
buf
,但是对于1KB,我怀疑您是否需要担心学习程序):

只需注意

关于另一个似乎困扰代码的问题(您已经注意到了),您的奇怪控制流。因此,简单的指导原则(注意:不是规则,只是指导原则)有望帮助您减少spagetti代码:

  • JMP
    (和条件跳转)应仅用于在同一过程中转到标签,否则您将开始绑定,因为您无法向后展开。其他唯一可以使用跳转的时间是用于尾部调用,但在这个阶段,您不必担心这一点,它更容易混淆

  • 当您要执行另一个过程时,始终使用
    CALL
    ,这允许您使用
    RETN
    /
    RET
    指令正确返回调用站点,从而使控制流更具逻辑性

一个简单的例子:

print_num: ;PROC: num to print in ecx, ecx is caller preserved
    push ecx
    push num_format ; "%d\n" 
    call _printf
    sub esp,8 ;cleanup for printf
    retn

print_loop_count: ;PROC: takes no args
    mov ecx,0x10 ;loop 16 times

do_loop: ;LABEL: used as a jump target for the loop
         ;good idea to prefix jump lables with "." to differentiate them
   push ecx ;save ecx
   call print_num ;value to print is already in ecx
   pop ecx ;restore ecx
   dec ecx
   jnz do_loop ;again?

   retn

您的问题直接归因于这样一个事实:在处理完字符串缓冲区后,您从未将nul终止符追加到它的末尾(据我所知,
read
syscall不会读回null)

不幸的是,由于您的控制流很奇怪,这有点难做到,但是更改
SetupBuf
应该可以做到(注意,您可能应该检查您没有溢出
buf
,但是对于1KB,我怀疑您是否需要担心学习程序):

只需注意

关于另一个似乎困扰代码的问题(您已经注意到了),您的奇怪控制流。因此,简单的指导原则(注意:不是规则,只是指导原则)有望帮助您减少spagetti代码:

  • JMP
    (和条件跳转)应仅用于在同一过程中转到标签,否则您将开始绑定,因为您无法向后展开。其他唯一可以使用跳转的时间是用于尾部调用,但在这个阶段,您不必担心这一点,它更容易混淆

  • 当您要执行另一个过程时,始终使用
    CALL
    ,这允许您使用
    RETN
    /
    RET
    指令正确返回调用站点,从而使控制流更具逻辑性

一个简单的例子:

print_num: ;PROC: num to print in ecx, ecx is caller preserved
    push ecx
    push num_format ; "%d\n" 
    call _printf
    sub esp,8 ;cleanup for printf
    retn

print_loop_count: ;PROC: takes no args
    mov ecx,0x10 ;loop 16 times

do_loop: ;LABEL: used as a jump target for the loop
         ;good idea to prefix jump lables with "." to differentiate them
   push ecx ;save ecx
   call print_num ;value to print is already in ecx
   pop ecx ;restore ecx
   dec ecx
   jnz do_loop ;again?

   retn

你应该使用调试器一步一步地调试你的程序,以便找出它的行为与你期望的不同之处;我刚刚开始学习x86汇编。一直在检查寄存器和地址等等。你对asm很了解吗?如果你仔细阅读了代码,你可能发现一行(或多行)特定的代码没有达到你的预期/意图?是的,我找到了。问题在于,它并不像剖析一个函数和简单地“看到”发生了什么那样简单。汇编是另一个野兽。我不知道这是否会有帮助,但我个人使用
jmp
转到另一个标签(在您的情况下,
读:
写:
,等等,而不是
ret
to
\u start:
)。我非常怀疑这是问题所在,但这是我的两分钱你应该使用调试器一步一步地调试你的程序,以便找出它的行为与你期望的不同之处;我刚刚开始学习x86汇编。一直在检查寄存器和地址等等。你对asm很了解吗?如果你仔细阅读了代码,你可能发现一行(或多行)特定的代码没有达到你的预期/意图?是的,我找到了。问题在于,它并不像剖析一个函数和简单地“看到”发生了什么那样简单。汇编是另一个野兽。我不知道这是否会有帮助,但我个人使用
jmp
转到另一个标签(在您的情况下,
读:
写:
,等等,而不是
ret
to
\u start:
)。我非常怀疑这是问题所在,但这是我的两分钱