1

I have an assignment regarding looping in Assembly. Nothing difficult since it's just the start of the course. I have done what was asked and just wanted to see if what I have done is correct. Also, I would like to know if there is anything that is un-needed or could be removed. (I enjoy seeing different ways to go about things and being able to see what is more efficient).

Evaluate the sum of 2n - 5, where n goes from 1 to 7

This is what I have done:

_num1
    DB    0

mov cx, 1    ; set counter to 1
mov eax, 0   ; use eax to keep total

eval:
    mov    [_num1], cx    ; set num1 to cx value
    shl    [_num1], 1     ; double value of num1
    add    eax, [_num1]   ; add values of 2n to eax
    sub    eax, 5         ; subtract 5 from eax (total)
    inc    cx             ; increment cx
    cmp    cx, 7          ; check if equal
    jne    eval

Should this work properly? If so, are there any ways of improving it? If not, what is wrong with the implementation?

8
  • What do mean "should it work properly"? Didn't you try it? Commented Feb 7, 2012 at 22:31
  • Do you have the capability to run this code at all? That should help you determine whether it works. Commented Feb 7, 2012 at 22:31
  • @CarlNorum & GregHewgill I currently don't have capability to run this. (I won't be able to until the end of the week). If the logic is correct, then I'm thinking I won't have to debug too much. On another note, I'm also doing the assignment early. Commented Feb 7, 2012 at 22:36
  • I recommend getting an assembler (nasm is free) and an assembly-level debugger (OllyDbg is also free). Programming in a vacuum is no fun at all. Commented Feb 7, 2012 at 22:43
  • @GregHewgill You are indeed correct :) I would have much preferred testing it myself. I have NASM at home, I just won't have access to it until the end of the week. Figured I would take a stab at it with notepad Commented Feb 8, 2012 at 0:17

1 Answer 1

3

Usually one counts CX down and loops until CX hits zero. There's the LOOP mnemonic which does exactly that in a single op. But these days the two commands "dec cx; jnz" combined are faster than LOOP on most CPUs. Use LOOP only when size-optimizing your code to the last bit.

Instead of using a memory reference (_num1) you could use the DX register, it's unused in your code. Registers are way faster than memory references.

Another often used opimization is using "xor eax,eax" instead of "mov eax,0". The MOV will be slower because it copies 4 bytes (0x00000000) from memory to the register. The XOR will clear the EAX register too, but without accessing any memory. It's also slightly smaller code.

As a personal preference, I'd go with higher-level comments. "increment cx" adds nothing to "inc cx". I prefer comments every couple of lines that are more on a high-level-language-level, like "eax = eax + 2*ecx".

More important is that you reserved only a byte for _num1, but then go on to assign two bytes (CX) to it. This will overwrite a byte of other data. If you want _num1 to hold two bytes, use "DW" instead of "DB". Another problem is that you mix operands and registers of different sizes. If you need 32 bit registers, stick with those. Or you could clear the upper 16 bits of the registers before using them. Or you can use the MOVZX mnemonic, which will clear the upper 16 bits when specifying data.

All in all:

  • Count downwards from 7 to 1 (use LOOP or DEC ECX;JNZ)
  • Use registers instead of memory references, if possible
  • Zero registers with the XOR op
  • Some small bugs
Sign up to request clarification or add additional context in comments.

6 Comments

Oh, and by the way: A good optimizing compiler would replace all the code with "21". But that's probably not the point.
Just a few questions. I was under the impression mov eax, 0 was immediate and didn't use memory. Thanks for the xor tip. Also thanks for the tip regarding comments. You are correct I need to change DB to DW. In the course I'm in, we haven't gone much into which registers to use for what (other than a select few). So would ECX be the proper counter? Lastly, I didn't mention this in my post, so it's my fault. We are required to mov from memory to register at least once, which is why I did so.
@StartingGroovy: mov eax, 0 indeed uses an immediate, but that only means that the loaded memory is directly in the instruction opcode, thus probably making the instruction longer. I think I read somewhere that mov eax, 0 doesn't break depencies on the old value of eax (with register renaming and such), but that might be different in modern processors.
Yeah, MOV EAX,0 just loads the zero from the instruction stream - it's encoded in the MOV-instruction. And ECX is usually used for counting.
@StartingGroovy: Testing against zero is simpler then testing against some abitrary number (the decrement will set the zero flag, so you don't need the cmp). On another note sub ecx, 1 might be more efficient then dec ecx nowadays (depending on the processor, but it will typically not be worse)
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.