我的第一个装配练习
我在 Visual Studio 2005 下使用汇编工作(我是新手),我想创建一个程序,用该规则计算算术级数: An = 2*An- 1 + An-2 但。我真的不知道如何使用寄存器,我只需要您提供一个示例即可继续我的练习。
这是我的代码:
.386
.MODEL flat,stdcall
.STACK 4096
extern ExitProcess@4:Near
.data
arraysize DWORD 10
setarray DWORD 0 DUP(arraysize)
firstvar DWORD 1
secondvar DWORD 2
.code
_main:
mov eax,[firstvar]
mov [setarray+0],eax
mov eax,[secondvar]
mov [setarray+4],eax
mov ecx, arraysize ;loop definition
mov ax, 8
Lp:
mov eax,[setarray+ax-4]
add eax,[setarray+ax-4]
add eax,[setarray+ax-8]
mov [setarray+ax],eax
add ax,4;
loop Lp
add ax,4;
push 0 ;Black box. Always terminate
call ExitProcess@4 ;program with this sequence
end _main ;End of program. Label is the entry point.
I'm working under visual studio 2005 with assembly (I'm a newbie) and I want to create a program that calculate arithmetic progression with that rule: An = 2*An-1 + An-2
but. I really don't know how to work with registers and I need just one example from you to continue with my exercises.
This is my code:
.386
.MODEL flat,stdcall
.STACK 4096
extern ExitProcess@4:Near
.data
arraysize DWORD 10
setarray DWORD 0 DUP(arraysize)
firstvar DWORD 1
secondvar DWORD 2
.code
_main:
mov eax,[firstvar]
mov [setarray+0],eax
mov eax,[secondvar]
mov [setarray+4],eax
mov ecx, arraysize ;loop definition
mov ax, 8
Lp:
mov eax,[setarray+ax-4]
add eax,[setarray+ax-4]
add eax,[setarray+ax-8]
mov [setarray+ax],eax
add ax,4;
loop Lp
add ax,4;
push 0 ;Black box. Always terminate
call ExitProcess@4 ;program with this sequence
end _main ;End of program. Label is the entry point.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不能同时使用 ax 作为索引寄存器和 eax 作为数据寄存器。对于 32 位代码,请坚持使用 32 位寄存器,除非您现在正在做什么。您无意中使用了 16 位寻址模式,您可能不想要这种模式。
永远不要使用循环指令,即使某些现代处理器可以快速执行(大多数不能)。
You can't use ax as index register and eax as data register at the same time. For 32bit code, stick to 32 bit registers, unless you now what you are doing. You inadvertedly used a 16 Bit addressing mode, which you probably didn't want.
Never ever use the loop instruction, even if some modern processors can execute ist fast (most can't).
我也是汇编初学者,但我的算法有点不同:
I'm a beginner in assembler too, but my algorithm is a bit different:
An = 2*An-1 + An-2 与斐波那契数列的公式几乎相同,因此您可以找到通过搜索可以找到很多有用的东西。 (例如此问答)。但我们需要的不仅仅是加法,而是 2a + b,而 x86 可以在一条 LEA 指令中完成此操作。
您永远不需要将循环变量存储在内存中,这就是寄存器的用途。因此,每次迭代不需要将数据从内存中拉回(往返大约 5 个周期的延迟),它可以只使用寄存器(0 个周期的额外延迟)。
您的数组可以放入 .bss,而不是 .data,因此您不会将这些零存储在目标文件中。
使用数组索引作为循环条件意味着我们总共只使用了 3 个寄存器,并且仍然不需要保存/恢复任何常用的调用保留寄存器 ESI、EDI、EBX 或 EBP。 (当然,呼叫者的 ESP 也会恢复)。
如果您关心性能,Intel SnB 系列 CPU 上的循环仅为 6 uops(融合域)。对于更大的数组大小,它可以每个时钟运行一个结果(每 2 个时钟迭代一次)。
An = 2*An-1 + An-2 is almost the same formula as the Fibonacci sequence, so you can find a lot of useful stuff by searching for that. (e.g. this q&a). But instead of just an add, we need 2a + b, and x86 can do that in one LEA instruction.
You never need to store your loop variables in memory, that's what registers are for. So instead of each iteration needing to pull data back out of memory (~5 cycles latency for a round trip), it can just use registers (0 cycles extra latency).
Your array can go in .bss, rather than .data, so you aren't storing those zeros in your object file.
Using the array index for the loop condition means we only used 3 registers total, and still don't need to save/restore any of the usual call-preserved registers ESI, EDI, EBX, or EBP. (And of course the caller's ESP is restored, too).
If you care about performance, the loop is only 6 uops (fused-domain) on Intel SnB-family CPUs. For bigger arraysize, it could run at one result per clock (one iteration per 2 clocks).