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