Assembly 程序集代码-找不到错误

Assembly 程序集代码-找不到错误,assembly,i386,Assembly,I386,我会感谢在我的代码中发现错误。我应该写一个函数,它把一个地址,字母l,数字n,和一个只能取2个值的递增变量:0和1。 如果递增变量为0,则函数应重复相同的字母n次。如果递增变量为1,则函数应返回后续字母字符串,例如“abcd…”(后续ascii字符)。 字母l决定以字符串开头的字母 我尝试使用ddd,它告诉我问题出在线路上 移动%ecx,(%edx) 我知道寄存器edx和ecx中有一个错误的值。 然而,我仍然不明白什么是错的,以及如何纠正它。我将非常感谢你的帮助 #include <std

我会感谢在我的代码中发现错误。我应该写一个函数,它把一个地址,字母l,数字n,和一个只能取2个值的递增变量:0和1。 如果递增变量为0,则函数应重复相同的字母n次。如果递增变量为1,则函数应返回后续字母字符串,例如“abcd…”(后续ascii字符)。 字母l决定以字符串开头的字母

我尝试使用ddd,它告诉我问题出在线路上 移动%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));
}

谢谢你的建议。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
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

谢谢你的建议。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
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

MOVL-bufor(%esp),%edx
也许你的意思是
LEAL-bufor(%esp),%edx
。很难说,因为您没有正确注释代码。此外,由于您现在显然可以使用
ddd
,单步执行代码并查看它在哪里出错,因此不要只查看出错指令。PS:
ebx
是被调用方保存的寄存器。我在代码中添加了注释。ddd中的一个步骤是如何实现的?每次我按下“步骤”,它都会告诉我程序没有运行。每次我运行程序时,它都会在我按下“步骤”之前完成。你可以在函数的开头或任何你想要的地方放置一个断点,然后你可以从那里开始单步执行。是的,要
复制地址
你需要使用
lea
而不是
mov
MOVL-bufor(%esp),%edx
也许你的意思是
LEAL-bufor(%esp),%edx
。很难说,因为您没有正确注释代码。此外,由于您现在显然可以使用
ddd
,单步执行代码并查看它在哪里出错,因此不要只查看出错指令。PS:
ebx
是被调用方保存的寄存器。我在代码中添加了注释。ddd中的一个步骤是如何实现的?每次我按下“步骤”,它都会告诉我程序没有运行。每次我运行程序时,它都会在我按下“步骤”之前完成。你可以在函数的开头或任何你想要的地方放置一个断点,然后你可以从那里开始单步执行。是的,要想
复制地址
,你需要使用
lea
而不是
mov
。理解为什么我在增加地址时应该添加$1而不是$4,我应该在该地址下插入下一个字符(因为它被转换为int)。字符串是字节数组。在内存中,每个元素是一个字节。当然,您可以动态转换为int,但在内存中,每个
char
都是一个字节。看起来您仍在破坏调用方的
%ebx
,因此如果从更复杂的调用函数使用,和/或在启用优化的情况下编译,您的代码将崩溃。看,还有其他关于ABI的东西,我添加了PUSHL%ebx和POPL%ebx。现在呢?我想当您修复
%ebx
错误时,您导致了另一个错误,因为您没有更改任何其他内容来解释您推送到堆栈上的额外4个字节。e、 g.您没有更改
MOVL n(%esp),%ecx
的偏移量。通常,您会首先保持
push%ebp
,并在堆栈上相对于它引用参数。(从
%ebp
到任何给定arg的偏移量对于整个函数来说都是一个常数,与到
%esp
的偏移量不同。这是使用ebp生成“堆栈帧”的主要好处:不必跟踪
%esp
指向args和局部变量的位置。)查看一些小函数的编译器输出(来自
gcc-m32-fno省略帧指针-O3
)例如。例如,演示制作堆栈帧,然后保存%ebx,并访问相对于%ebp的函数arg。Clang的版本奇怪地不是最佳的(使用
push%eax
保留空间/对齐堆栈,然后
mov%eax,(%esp)
计算值后。)gcc的版本有一种有趣的方法,可以在调用后清理堆栈,使用
mov
加载ebx,然后使用
leave
而不是
pop%ebp
。理解为什么我在增加地址时应该添加$1而不是$4,在地址下面我应该插入下一个字符(自转换为int后)。字符串是一个字节数组。在内存中,每个元素都是一个字节。当然,您可以动态转换为int,但在内存中,每个
char
都是一个字节。看起来您仍在破坏调用方的
%ebx
,因此,如果从更复杂的调用函数中使用代码,和/或使用优化编译,则代码将崩溃已启用。请参阅,以及其他关于ABI的内容。我添加了PUSHL%ebx和POPL%ebx。现在呢?我认为您在修复
%ebx
错误时导致了另一个错误,因为您没有更改任何其他内容来解释推送到堆栈上的额外4个字节。例如,您没有更改
MOVL n(%esp)的偏移量,%ecx
。通常,您会首先保持
推送%ebp
,并在堆栈上相对于它引用参数。(从
%ebp
到任何给定参数的偏移量对于整个函数来说是一个常量,而不是
%esp
的偏移量。这是主要参数