我的第一个装配练习

发布于 2024-10-04 03:24:13 字数 935 浏览 6 评论 0原文

我在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

笑着哭最痛 2024-10-11 03:24:14

不能同时使用 ax 作为索引寄存器和 eax 作为数据寄存器。对于 32 位代码,请坚持使用 32 位寄存器,除非您现在正在做什么。您无意中使用了 16 位寻址模式,您可能不想要这种模式。

mov ecx, arraysize-1              ;loop definition
mov ebx, 8

Lp:
mov eax,[setarray+ebx-4]
add eax,[setarray+ebx-4]
add eax,[setarray+ebx-8]
mov [setarray+ebx],eax

add ebx,4
dec ecx
jnc Lp

永远不要使用循环指令,即使某些现代处理器可以快速执行(大多数不能)。

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.

mov ecx, arraysize-1              ;loop definition
mov ebx, 8

Lp:
mov eax,[setarray+ebx-4]
add eax,[setarray+ebx-4]
add eax,[setarray+ebx-8]
mov [setarray+ebx],eax

add ebx,4
dec ecx
jnc Lp

Never ever use the loop instruction, even if some modern processors can execute ist fast (most can't).

情定在深秋 2024-10-11 03:24:14

我也是汇编初学者,但我的算法有点不同:


    A   dword   1026 dup (0)          ; declare this in the data segm.

; ...

    mov     esi, offset A         ; point at the results array
    mov     [esi], 1               ; initialize A(0)
    mov     [esi + 4], 2           ;  and A(1)
    xor  ecx, ecx

lp: 添加 esi, 8
mov eax, [esi - 4] ;得到 A(n-1)
添加 eax, eax ;加倍
添加 eax, [esi - 8] ;计算 A(n)
mov [esi], eax ;并保存它
包括 ecx ;下一个n
cmp ecx,n;确保 n 是双字,使用
; cmp ecx,双字 ptr n ;如果不是
jb LP ;循环直到 ecx < n
;
;现在你应该在 A 数组中得到结果
; esi 指向它的末尾

我没有编译它来看看是否运行良好,但它应该..

I'm a beginner in assembler too, but my algorithm is a bit different:


    A   dword   1026 dup (0)          ; declare this in the data segm.

; ...

    mov     esi, offset A         ; point at the results array
    mov     [esi], 1               ; initialize A(0)
    mov     [esi + 4], 2           ;  and A(1)
    xor  ecx, ecx

lp: add esi, 8
mov eax, [esi - 4] ; get A(n-1)
add eax, eax ; double it
add eax, [esi - 8] ; computes A(n)
mov [esi], eax ; and save it
inc ecx ; next n
cmp ecx, n ; be sure n is a dword, use
; cmp ecx, dword ptr n ; if it isn't
jb lp ; loop until ecx < n
;
; now you should have the results in the A array with
; esi pointing to the end of it

I didn't compiled it to see if works well but it should..

红颜悴 2024-10-11 03:24:14

An = 2*An-1 + An-2 与斐波那契数列的公式几乎相同,因此您可以找到通过搜索可以找到很多有用的东西。 (例如此问答)。但我们需要的不仅仅是加法,而是 2a + b,而 x86 可以在一条 LEA 指令中完成此操作。

您永远不需要将循环变量存储在内存中,这就是寄存器的用途。因此,每次迭代不需要将数据从内存中拉回(往返大约 5 个周期的延迟),它可以只使用寄存器(0 个周期的额外延迟)。

您的数组可以放入 .bss,而不是 .data,因此您不会将这些零存储在目标文件中。

arraysize equ 10     ; not DWORD: this is an assemble-time constant, not a value stored in memory

.bss
seq  DWORD 0 DUP(arraysize)   ; I think this is the right MASM syntax?
; NASM equivalent:  seq RESD arraysize

.code
_main:

    mov  edx, 1         ; A[0]
    mov  [seq], edx
    mov  eax, 2         ; A[1]
    mov  [seq+4], eax

    mov  ecx, 8         ; first 8 bytes stored
    ; assume the arraysize is > 2 and even, so no checks here
seqloop:
    lea  edx, [eax*2 + edx]  ;    edx=A[n],   eax=A[n-1]
    mov  [seq + ecx], edx    ; or edx=A[n-1], eax=A[n-2]
    lea  eax, [edx*2 + eax]  
    mov  [seq + ecx + 4], eax
    ; unrolled by two, so we don't need any MOV or XCHG instructions between registers, or any reloading from memory.

    add  ecx, 8             ; +8 bytes
    cmp  ecx, arraysize*4   ; (the *4 happens at assemble time)
    jb   seqloop

    ret

使用数组索引作为循环条件意味着我们总共只使用了 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.

arraysize equ 10     ; not DWORD: this is an assemble-time constant, not a value stored in memory

.bss
seq  DWORD 0 DUP(arraysize)   ; I think this is the right MASM syntax?
; NASM equivalent:  seq RESD arraysize

.code
_main:

    mov  edx, 1         ; A[0]
    mov  [seq], edx
    mov  eax, 2         ; A[1]
    mov  [seq+4], eax

    mov  ecx, 8         ; first 8 bytes stored
    ; assume the arraysize is > 2 and even, so no checks here
seqloop:
    lea  edx, [eax*2 + edx]  ;    edx=A[n],   eax=A[n-1]
    mov  [seq + ecx], edx    ; or edx=A[n-1], eax=A[n-2]
    lea  eax, [edx*2 + eax]  
    mov  [seq + ecx + 4], eax
    ; unrolled by two, so we don't need any MOV or XCHG instructions between registers, or any reloading from memory.

    add  ecx, 8             ; +8 bytes
    cmp  ecx, arraysize*4   ; (the *4 happens at assemble time)
    jb   seqloop

    ret

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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文