gpt4 book ai didi

linux - 输入一串字符并输出为大写

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:40:49 25 4
gpt4 key购买 nike

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

我认为代码中存在的其他问题如下:

  • 一些子例程在调用结束时使用ret。我遇到的问题是弄清楚这些子例程中的哪些实际上不需要ret,最好与jmp一起使用.老实说,我在这里对两者的语义有点困惑。例如,使用 ja 调用的子例程是否需要在调用结束时被ret

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

完整程序如下。

编码器

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 系统调用不会读回一个空值)。

不幸的是,由于你奇怪的控制流程,这有点难做,但改变 SetupBuf 应该可以解决问题(注意,你应该检查你没有溢出 buf ,但是对于 1KB,我怀疑你需要为学习程序担心):

SetupBuf:
mov ecx, esi
mov ebp, buf
mov [ebp+ecx],0 ;make sure the string is nul terminated
dec ebp
ret

注意

关于另一个似乎困扰您的代码的问题(您已经恰本地注意到),您的奇怪控制流。如此简单的指南(注意:不是规则,只是指南)希望能帮助您减少意大利面条式代码:

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

  • 当您要转到另一个过程时,请始终使用 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

关于linux - 输入一串字符并输出为大写,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11303336/

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