2016-06-25 17 views
1

Я буду благодарен за обнаружение ошибок в моем коде. Я должен был написать функцию, которая берет адрес в буфер, букву l, число n и переменную увеличения, которая может принимать только 2 значения: 0 и 1. Если переменная увеличения равна 0, функция должна повторяйте одно и то же письмо n раз. Если переменная увеличения равна 1, функция должна возвращать строку последующих букв, например «abcd ....» (последующие символы ascii). Буква l определяет, какую букву мы начинаем со строки.Код сборки - не найдена ошибка

Я попытался с помощью DDD, он говорит мне, что проблема с линией MOVL% ECX, (% EDX) И я знаю, что есть неправильное значение в регистре EDX и ECX. Все еще, я не могу понять, что не так и как исправить. Я буду очень благодарен за помощь.

#include <stdio.h> 
#include <stdlib.h> 
extern char * generate_str(char * s, int c, int n, int inc); 

int main() 
{ 
    char s[100] = "something"; 
    char c = 'a'; 
    int n = 5; 
    int inc = 0; 
    printf("String %s\n", generate_str(s, (int)c, n, inc)); 
} 

код сборки:

.data 
character: .int 0 

# char -> 1 
# int -> 4 
# arguments: char * s, int c, int n, int inc 

.equ bufor,8 
.equ c,12 
.equ n,16 
.equ inc,20 
#eax, ebx, ecx, edx 

.text 
.type generate_str, @function 
.global generate_str 

generate_str: 

    PUSHL %ebp   #prolog of the function 
    MOVL %esp, %ebp 
    MOVL inc(%esp), %eax #copy variable inc into eax 
    MOVL n(%esp), %ebx #copy variable n into ebx 
    PUSHL %ecx   #save contents of ecx 
    MOVL c(%esp), %ecx #copy variable c into ecx temporarily 
    MOVL %ecx, character #copy variable c into reserved memory called character 
    POPL %ecx    #restore contents of c 
    MOVL bufor(%esp), %edx #copy addres of a buffer into edx 

    CMP $0, %eax # eax > 0 ? #is inc variable 0 or 1 
    JA one     #if it is 1, go to line "one" 
    MOVL %ebx, %ecx   %copy value of variable n into ecx, it tells how many letters should be placed in the buffer 
p: 
    PUSHL %ecx    #save contents of ecx 
    MOVL character, %ecx  #copy character into ecx 
    MOVL %ecx, (%edx)   #copy character into the place in the memory which address is given in edx 
    POPL %ecx     #restore contents of ecx 
    ADDL $4, %edx    #increase value of edx by 4, so we move forwards in the memory to save another letter there 
    loop p     #loop until ecx is 0 
    jmp end     #jump to the final part of the function 

one:       #if the value of inc is 1 then do another loop 
    PUSHL %ecx    #save ecx and use this register to copy character into the place in memory which address is in the edx registry 
    MOVL character, %ecx 
    MOVL %ecx, (%edx) 
    POPL %ecx 
    ADDL $1, character  #increase ascii character by 1 
    ADDL $4, %edx    #move in memory by 4 bytes so we can save the next letter 
    loop one     #continue loop until ecx is zero 
    jmp end 

end: 
    MOVL %edx, %eax   #copy address of the final string into eax 
    movl %ebp,%esp   #restore registers 
    popl %ebp 
RET 
+1

'MOVL bufor (% особ),% edx' может быть, вы имели в виду' Лил bufor (% особ),% edx'. Трудно сказать, потому что вы не прокомментировали свой код должным образом. Кроме того, поскольку теперь вы можете, по-видимому, использовать 'ddd', сделать один шаг кода и посмотреть, где он делает что-то неправильно, не просто взглянуть на инструкцию о сбоях. PS: 'ebx' является зарегистрированным регистром. – Jester

+0

Я добавил комментарии к коду. Как сделать один шаг в ddd? Каждый раз, когда я нажимаю «step», он говорит мне, что программа не запускается. Каждый раз, когда я запускаю программу, она заканчивается, прежде чем я могу нажать «шаг». – Joanna

+0

Вы устанавливаете точку останова в начале вашей функции или где хотите, тогда вы можете сделать один шаг оттуда. Да, для «копирования адреса» вам нужно использовать 'lea' not' mov'. – Jester

ответ

0

Спасибо за ваши советы. DDD выполнил свою работу. Вот скорректированный код. Честно говоря, у меня все еще есть проблемы с пониманием того, почему я должен был добавить $ 1 вместо $ 4, когда я увеличивал адрес, под которым я должен был вставить следующий символ (поскольку он был преобразован в int), но он работает.

#include <stdio.h> 
#include <stdlib.h> 
extern char * generate_str(char * s, int c, int n, int inc); 

int main() 
{ 
    char s[100] = "cos tam"; 
    char c = 'a'; 
    int n = 5; 
    int inc = 0; 
    printf("String %s\n", (char*) generate_str(s, (int)c, n, inc)); 

} 

код сборки:

#dane 
.data 
character: .int 0 

# char -> 1 
# int -> 4 
# arguments: char * s, int c, int n, int inc 

.equ bufor,8 
.equ c,12 
.equ n,16 
.equ inc,20 
#eax, ebx, ecx, edx 

.text 
.type generate_str, @function 
.global generate_str 

generate_str: 
    PUSHL %ebp 
    MOVL %esp, %ebp 
    MOVL inc(%esp), %eax 
    MOVL n(%esp), %ecx 
    MOVL c(%esp), %ebx 
    MOVL bufor(%esp), %edx 
    PUSHL %ebx  

    CMP $0, %eax 
    JA one 
p: 
    MOVL %ebx, (%edx) 
    ADDL $1, %edx 
    loop p 
    ADDL $0, %edx 
    jmp end 

one: 
    MOVL %ebx, (%edx) 
    ADDL $1, %ebx 
    ADDL $1, %edx 
    loop one  
    ADDL $0, %edx 
    jmp end 

end: 
    MOVL bufor(%esp), %edx 
    MOVL %edx, %eax 
    movl %ebp,%esp 
    popl %ebx 
    popl %ebp 
    RET 

И версия, которая использует переменную

#dane 
.data 
letter: .int 0 

# char -> 1 
# int -> 4 
# arguments: char * s, int c, int n, int inc 

.equ bufor,8 
.equ c,12 
.equ n,16 
.equ inc,20 
#eax, ebx, ecx, edx 

.text 
.type generate_str, @function 
.global generate_str 

generate_str: 
    PUSHL %ebp 
    MOVL %esp, %ebp 
    MOVL inc(%esp), %eax 
    MOVL n(%esp), %ecx 
    MOVL c(%esp), letter 
    MOVL bufor(%esp), %edx 
    PUSHL %ebx 

    CMP $0, %eax 
    JA one 
p: 
    MOVL letter, %edi 
    MOVL %edi, (%edx) 
    ADDL $1, %edx 
    loop p 
    jmp end 

one: 
    MOVL %ebx, (%edx) 
    ADDL $1, %ebx 
    ADDL $1, %edx 
    loop one 
    ADDL $0, %edx 
    jmp end 

end: 
     MOVL bufor(%esp), %edx 
     MOVL %edx, %eax 
     MOVL %ebp,%esp 
     popl %ebx 
     popl %ebp 
     RET 
+0

* понимание, почему я должен был добавить $ 1 вместо $ 4, когда я увеличивал адрес, под которым я должен был вставить следующий символ (так как он был преобразован в int) *. Строка представляет собой массив байтов. В памяти каждый элемент представляет собой один байт. Конечно, вы можете конвертировать «на лету» в int, но * в память *, каждый символ «char» - один байт. –

+0

Похоже, что вы все еще уничтожаете '% ebx' вызывающего абонента, поэтому ваш код будет сбой при использовании из более сложной вызывающей функции и/или при компиляции с оптимизацией. См. Http://stackoverflow.com/questions/8335582/why-does-ia-32-have-a-non-intuitive-caller-and-callee-register-saving-convention и другие сведения об ABI в [x86 tag wiki] (http://stackoverflow.com/tags/x86/info) –

+0

Я добавил PUSHL% ebx и POPL% ebx. Как насчет сейчас? – Joanna

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

  • Нет связанных вопросов^_^