程序集从一个数组复制到另一个数组
Assembly copying from one array to another
对不起,这个标题,我想不出用英语表达的方式。
所以我正在为一门课程编写一个汇编小游戏,并且在两个 for 循环中,我将像素数据从 "bomb" 像素向量复制到 "area" 像素向量,稍后将被绘制到屏幕上。在 C 中,它应该如下所示:
int x, y;
for(int i=0;i<32;i++)
for(int j=0;j<32;j++)
area[x+i][y+j]=bomb[i][j];
使用masm汇编器和notepad++编写代码,得到
mov ecx, 0 ; my i
outerloop:
cmp ecx, 32
je done
mov esi, 0 ; my j
innerloop:
mov ebx, sprite_width ; sprite_width=32
mov eax, ecx
mul ebx
add eax, esi
shl eax, 2
mov edi, bomb
add edi, eax
mov pixel, edi ; pixel = bomb[i][j]
mov ebx, area_width
mov eax, y
add eax, ecx
mul ebx
add eax, x
add eax, esi
shl eax, 2
mov edi, area
add edi, eax
mov eax, [pixel]
mov dword ptr [edi], eax ; should be area[x+i][y+j] = pixel
cmp esi, 32
je innerloopdone
inc esi
jmp innerloop
innerloopdone:
inc ecx
jmp outerloop
done:
在这之后,屏幕上的 32x32 区域应该看起来像一个炸弹,因为炸弹矢量是如何写的,但是我只看到一些绿色和一些蓝色。蓝色甚至根本不在炸弹向量中。 loop/logic有没有错误?
由于您没有 post 这些符号的定义,我只是猜测它们是如何定义的,我希望是这样的:
area dd 640*480 dup (0) ; 640x480x32bpp "screen area"
area_width dd 640
sprite_width dd 32
sprite_height dd 32
bomb dd 32*32 dup (255) ; 32x32 red pixels as "bomb" gfx placeholder
那么这应该足以以比您的建议更有效的方式绘制非透明图形:
; initialize registers before drawing lines
; make edi = address area[y][x]
lea edi,[area]
mov ebx,[area_width]
mov eax,[y]
mul ebx
add eax,[x] ; eax = y*area_width + x
shl eax,2
add edi,eax ; edi = area + (y*area_width + x)*4
; make ebx = (area_width - sprite_width)*4
sub ebx,[sprite_width]
shl ebx,2
; make esi = address bomb[0][0]
lea esi,[bomb]
; make edx = number of lines
mov edx,[sprite_height] ; 32
line_loop:
; draw single line
mov ecx,[sprite_width]
rep movsd
; move to the next line (esi already updated, edi must advance)
add edi,ebx
; loop until all lines are drawn
dec edx
jnz line_loop
我没有调试,所以可能有问题,但是我没有MASM可以试。
关于您的原始代码,有一个反复出现的主题,您在其中编写了如下内容:
mov edi, bomb
对
mov eax, [pixel]
不幸的是,在 MASM 中这些是相同的,当您使用 symbol
名称时不需要 []
内存访问,即 mov edi,bomb
是从内存加载值,而不是获取地址炸弹。要获取地址,请在 MASM 中使用 mov edi,OFFSET bomb
,或 lea edi,[bomb]
.
所以你混淆了那些,有时看起来你确实想要获取内存地址,有时想要值,有时你将地址而不是值存储到内存中,等等...
此外,我强烈建议您开始在符号周围使用 []
,即使 MASM 不需要它们,这样访问内存的代码行在视觉上更容易被发现,并且样式与 indirect 相同通过寄存器寻址(即与 mov eax,[ebx]
相同的样式,其中甚至 MASM 也需要方括号)。检查我的示例,我如何在每次内存访问时始终如一地使用 []
(lea
除外,其中 CPU 将 不 访问内存,仅计算地址,但这是由于 lea
指令本身的性质,它的参数仍然是内存访问类型)。
但最重要的是为您的平台找到一些可用的调试器,并学习使用它,因为没有调试器的汇编编程就像试图 assemble 蒙住眼睛的机器人。您可以做到,但要困难得多,并且需要很多技巧和经验。这是你现在的主要问题,你代码的代码风格和效率大约是你问题的10%,无法调试你的代码是90%。
对不起,这个标题,我想不出用英语表达的方式。 所以我正在为一门课程编写一个汇编小游戏,并且在两个 for 循环中,我将像素数据从 "bomb" 像素向量复制到 "area" 像素向量,稍后将被绘制到屏幕上。在 C 中,它应该如下所示:
int x, y;
for(int i=0;i<32;i++)
for(int j=0;j<32;j++)
area[x+i][y+j]=bomb[i][j];
使用masm汇编器和notepad++编写代码,得到
mov ecx, 0 ; my i
outerloop:
cmp ecx, 32
je done
mov esi, 0 ; my j
innerloop:
mov ebx, sprite_width ; sprite_width=32
mov eax, ecx
mul ebx
add eax, esi
shl eax, 2
mov edi, bomb
add edi, eax
mov pixel, edi ; pixel = bomb[i][j]
mov ebx, area_width
mov eax, y
add eax, ecx
mul ebx
add eax, x
add eax, esi
shl eax, 2
mov edi, area
add edi, eax
mov eax, [pixel]
mov dword ptr [edi], eax ; should be area[x+i][y+j] = pixel
cmp esi, 32
je innerloopdone
inc esi
jmp innerloop
innerloopdone:
inc ecx
jmp outerloop
done:
在这之后,屏幕上的 32x32 区域应该看起来像一个炸弹,因为炸弹矢量是如何写的,但是我只看到一些绿色和一些蓝色。蓝色甚至根本不在炸弹向量中。 loop/logic有没有错误?
由于您没有 post 这些符号的定义,我只是猜测它们是如何定义的,我希望是这样的:
area dd 640*480 dup (0) ; 640x480x32bpp "screen area"
area_width dd 640
sprite_width dd 32
sprite_height dd 32
bomb dd 32*32 dup (255) ; 32x32 red pixels as "bomb" gfx placeholder
那么这应该足以以比您的建议更有效的方式绘制非透明图形:
; initialize registers before drawing lines
; make edi = address area[y][x]
lea edi,[area]
mov ebx,[area_width]
mov eax,[y]
mul ebx
add eax,[x] ; eax = y*area_width + x
shl eax,2
add edi,eax ; edi = area + (y*area_width + x)*4
; make ebx = (area_width - sprite_width)*4
sub ebx,[sprite_width]
shl ebx,2
; make esi = address bomb[0][0]
lea esi,[bomb]
; make edx = number of lines
mov edx,[sprite_height] ; 32
line_loop:
; draw single line
mov ecx,[sprite_width]
rep movsd
; move to the next line (esi already updated, edi must advance)
add edi,ebx
; loop until all lines are drawn
dec edx
jnz line_loop
我没有调试,所以可能有问题,但是我没有MASM可以试。
关于您的原始代码,有一个反复出现的主题,您在其中编写了如下内容:
mov edi, bomb
对
mov eax, [pixel]
不幸的是,在 MASM 中这些是相同的,当您使用 symbol
名称时不需要 []
内存访问,即 mov edi,bomb
是从内存加载值,而不是获取地址炸弹。要获取地址,请在 MASM 中使用 mov edi,OFFSET bomb
,或 lea edi,[bomb]
.
所以你混淆了那些,有时看起来你确实想要获取内存地址,有时想要值,有时你将地址而不是值存储到内存中,等等...
此外,我强烈建议您开始在符号周围使用 []
,即使 MASM 不需要它们,这样访问内存的代码行在视觉上更容易被发现,并且样式与 indirect 相同通过寄存器寻址(即与 mov eax,[ebx]
相同的样式,其中甚至 MASM 也需要方括号)。检查我的示例,我如何在每次内存访问时始终如一地使用 []
(lea
除外,其中 CPU 将 不 访问内存,仅计算地址,但这是由于 lea
指令本身的性质,它的参数仍然是内存访问类型)。
但最重要的是为您的平台找到一些可用的调试器,并学习使用它,因为没有调试器的汇编编程就像试图 assemble 蒙住眼睛的机器人。您可以做到,但要困难得多,并且需要很多技巧和经验。这是你现在的主要问题,你代码的代码风格和效率大约是你问题的10%,无法调试你的代码是90%。