0

and sorry for the title, i couldn't imagine a way to express this in english. So i'm writing a little game in assembly for a course, and, inside of two for loops, i copy the pixel data from the "bomb" vector of pixels, to the "area" vector of pixels, which will later be drawn to the screen. In C, it should look like this:

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];

Using masm assembler and notepad++ to write the code, i got

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:

After this, the 32x32 area in the screen should look like a bomb, because of how the bomb vector is written, however i only see some green and some blue. Blue is not even in the bomb vector at all. Is there any mistake in the loop/logic?

Adrian
  • 3
  • 3
  • yes. (there is some mistake for sure, I see at least one) Did you debug your code in debugger? Try it, to identify all unexpected things happening). BTW your "draw bomb" is of very naive and inefficient approach to similar kind of problems, the C variant would be much more efficient. Plus I believe the C should be `area[y+i][x+j]` (y is first, right?). – Ped7g May 19 '18 at 15:12

1 Answers1

4

As you didn't post definitions of those symbols, I'm just guessing how they were defined, I would expect something like:

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

Then this should be enough to draw non-transparent piece of graphics in a bit more efficient way than your proposal:

    ; 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

I didn't debug it, so there may be a problem, but I don't have MASM to try.


About your original code, there's recurring theme where you write things like:

    mov edi, bomb

vs

    mov eax, [pixel]

Unfortunately in MASM these are identical, the [] memory access is not needed when you use symbol name, i.e. the mov edi,bomb is loading value from memory, not getting address of bomb. To get address use mov edi,OFFSET bomb in MASM, or lea edi,[bomb].

So you mix up those, and sometimes it looks like you did want to get memory address, and sometimes value, and sometimes you store address into memory instead of value, etc...

Also I strongly suggest you to start using [] around symbols even when the MASM doesn't require them, so the lines in code accessing memory are visually easier to spot, and the style is identical with indirect addressing through registers (i.e. same style as mov eax,[ebx], where even MASM needs square brackets). Check my example, how I consistently use [] around every memory access (except lea, where the CPU will not access memory, only calculate address, but that's due to nature of lea instruction itself, the argument for it is still memory-access-type).

But most importantly find some working debugger for your platform, and learn to use it, because programming in assembly without debugger is like trying to assemble robot blindfolded. You can do it, but it's much more difficult and requires lot of skill and experience. This is your major problem right now, the code style and efficiency of your code is like 10% of your problem, not being able to debug your code is 90%.

Ped7g
  • 16,236
  • 3
  • 26
  • 63
  • Our professor encouraged us to use [OllyDbg](http://www.ollydbg.de/) but i just fail to see where it could be of help. As in, it would take me a lot more to learn it's use than to blindly write code. – Adrian May 19 '18 at 20:20
  • @Adrian eeee.. do you mean to "write code" or "write working code"? Because you didn't manage the second one yet, so the time is still counting, and it will probably outgrow the time needed to learn basic usage of debugger quickly. If you are just interested into "writing code", then yes, that's valid strategy, but then don't ask others to debug and fix it for you. ... Just for fun, try to fix your original code, now when you know it is wrong and not working. GL HF. – Ped7g May 19 '18 at 20:28
  • Was not trying to be mean. Your code crashes at `rep movsd`, could you figure out why? – Adrian May 19 '18 at 20:40
  • @Adrian probably the `edi` is wrongly calculated, or your `area` buffer is not writeable. Seems ok from the code, so without actually seeing the crash conditions in debugger I have no idea. Or your data are not defined in a way as in my example. ... edit: did reread the code, and I'm 90% sure it's correct, when other prerequisites are, so no idea at all. Provide [MCVE] – Ped7g May 19 '18 at 21:30
  • @Adrian: I totally agree with Ped7g: using a debugger makes it vastly easier to learn asm. Otherwise all you know is that your code crashed somewhere. Being able to see register values, and single-step to make sure your code branches the way you expect for given inputs, is a *huge* advantage. You don't need to learn all of a debugger's features for it to be useful, just how to set a breakpoint, single-step, and examine registers / memory. – Peter Cordes May 19 '18 at 23:27
  • @Adrian about "all you know is that your code crashed" is actually the better situation, but without using debugger you will sometimes get into situation where you finish some code, run it, the output is correct, and you proceed to continue with writing another part of code, not even having clue that the correct output was just lucky accident of particular input, and in reality the code you did write behaves completely different than you expected, calculating wrong values in other cases, or overwriting memory or crashing... In asm I highly recommend to meticulously verify every new line in dbg – Ped7g May 20 '18 at 06:39
  • The error appears on this line: `rep movsd` . Ollydbg says _Access violation when writing to [00E7A513]_ . I do not know how to use this information. – Adrian May 20 '18 at 12:52
  • `0x00E7A513` is the address where the `movsd` tried to write and it's not write-able memory. Now check what is the memory area reserved by `area` line (some memory address like for example `area = 0x1200`. Then check your x and y coordinates used, let's say [7, 24] and area width being 640, then the target address should be 0x1200 + (24*640+7)*4 = 66076 (0x1021C) ... if the `edi` would be in such case before first `rep movsd` equal to 0x1021C, then the address calculation is correct, and your area definition is wrong. If the `edi` is for example 0xE021C, then calcuation is wrong. – Ped7g May 20 '18 at 14:01