2012-07-03 2 views
1

Я пытаюсь написать программу, которая преобразует строчную строку символов в верхний регистр, используя буфер для хранения начальной строки. Проблема, с которой я столкнулся, заключается в том, что моя программа будет печатать бесконечный цикл символов, которые должны соответствовать последовательности, которую я ему дал.Введите строку символов и вывод в верхний регистр

Другие проблемы, которые я считаю, существуют в коде следующим образом:

  • Некоторые подпрограммы используют ret в конце вызова. Проблема, с которой у меня возникают проблемы, заключается в том, что вы обнаруживаете , который этих подпрограмм действительно не нужен ret, и их лучше использовать с jmp. Честно говоря, я немного запутался здесь между семантикой этих двух. Например, подпрограмма, вызываемая с ja, должна быть ret 'ed в конце вызова?

  • Я также пытаюсь напечатать количество итераций, которые происходят в каждой итерации цикла, используемого для преобразования значений. По какой-то причине я сделаю счетчик и решит его распечатать с помощью рутинной игры 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 
+0

Вы должны использовать отладчик для пошагового вашей программы, чтобы выяснить, где его поведение отклоняется от того, что вы ожидаете. –

+0

Отлажено много; Я только начал изучать сборку x86. Проверяли регистры и адреса, а что нет. Знаете ли вы, как хорошо? – zeboidlund

+0

Если вы прошли через код, предположительно, вы нашли одну (или несколько) конкретных строк, которые не выполняют то, что вы ожидали/планировали? –

ответ

4

Ваша проблема напрямую связана с тем, что вы никогда не присоединять NUL терминатора к концу вашего буфера строки, как только вы закончите его обработку (от того, что я помню, read syscall не возвращает значение null).

, к сожалению, это немного сложнее сделать из-за вашего нечетного потока управления, но изменение SetupBuf следует сделать трюк (обратите внимание, вы, вероятно, следует проверить, что вы не разливалась buf, но с 1KB, я сомневаюсь, что ты» d нужно беспокоиться по программе обучения):

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

Сразу отметим

по другому вопросу, который, кажется, чума код (который вы метко заметили), ваш странный поток управления. Поэтому простые рекомендации (примечание: не правила, только руководящие принципы), которые, надеюсь, помогут вам на вашем пути к менее Спагетти код:

  • 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 
+0

+1 Хороший ответ. – Rob

Смежные вопросы