초기 문자열을 저장하는 버퍼를 사용하여 소문자 문자열을 대문자로 변환하는 프로그램을 작성하려고합니다. 내가 겪고있는 문제는 내 프로그램이 내가 준 문자열과 닮아야하는 무한 루프의 문자를 출력한다는 것이다.문자열을 입력하여 대문자로 출력하십시오.
일부 서브 루틴 호출의 끝에서
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
당신은 그 동작은 당신이 무엇을 기대에서 발산 곳을 찾기 위해, 당신의 프로그램을 통해 단계별로 디버거를 사용합니다. –
디버깅을 많이했습니다. 방금 x86 어셈블리를 배우기 시작했습니다. 레지스터와 주소를 확인하고 있었는지 확인했습니다. 잘 아십니까? – zeboidlund
코드를 단계별로 살펴본 결과 예상/의도하지 않은 특정 행이 하나 이상 발견되었을 것입니다. –