0

I am tasked to write a GNU assembly program using Intel syntax which counts numbers in array which are <= 6
I came up with the following code:

.intel_syntax noprefix
.data
    n: .word 5
    a: .word 1, 6, 7, 4, 8
    r: .word 0

.text
.global main
main:

    mov cx, n
    mov al, 0

    mov eax, 0
            
l1: cmpw [a+eax*2], 6
    ja l2
    inc al
l2: inc eax
    loop l1
    
    mov r, al
    ret

However while debugging it with GDB it seems to output 8 to variable r which is incorrect for given data.

1

1 Answer 1

2

You seem to think al and eax are two independent registers, but actually, al is just the lowest byte of eax, so you were using the same register for two different things at the same time. Use another register like edx as your array index instead of eax.

Also, you're almost certainly not running in 16-bit mode, so loop won't just check cx, so the high bits of it will make the loop run more times than you want. Do mov ecx, n instead and also .long 5 instead of .word 5. (Or you could use loopw l1 instead of loop l1 if you're on 32-bit and really want to stick with just cx for some reason.)

Sign up to request clarification or add additional context in comments.

5 Comments

16-bit mode (on a 386 or later) allows 32-bit operand-size and address-size, the same way 32-bit mode allows 16-bit operand-size and address-size. But using GAS and GDB with a main: that can ret is vastly more likely to be 32-bit mode under a modern OS like GNU/Linux, not 16-bit code, so yes, the ultimate point is correct, use ECX. (And prefer n=5 as an assemble-time constant; there's no reason to have 5 as a word or dword in memory in the .data section, an immediate would work fine.)
@PeterCordes Doesn't the LOOP instruction only care about the address size, though? Or do you mean it's legal to use eax in 16-bit code?
Yes, so if you assembled this code for 16-bit mode, cmpw [a+eax*2], 6 would use an address-size override (0x67) to allow a 32-bit addressing mode (instead of a 0x66 for 16-bit operand-size in 32-bit mode). And loop without an addr32 override would use CX like this code is expecting. Try it with .code16 at the top of the file if you're curious. (And the terrible way to fix this code for 32-bit mode would be addr16 loop l1.)
@PeterCordes Huh, I didn't know 16-bit supported that. Also, it looks like loopw works as an alternative to addr16 loop.
Yeah, when 386 was new, Intel a lot of their CPUs would get used in 16-bit real mode most of the time, so new features usable in the existing mode would be useful. And there was enough coding-space left at that point to introduce 2 prefix bytes into the existing mode. Unlike when amd64 was new and they needed to repurpose some existing encodings since 32-bit mode had no unused single bytes for the start of an instruction.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.