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.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
H4kt
  • 133
  • 7
  • Does this answer your question? [How do AX, AH, AL map onto EAX?](https://stackoverflow.com/questions/15191178/how-do-ax-ah-al-map-onto-eax) – Peter Cordes May 24 '22 at 02:24

1 Answers1

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

  • 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.) – Peter Cordes May 24 '22 at 02:24
  • @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? – Joseph Sible-Reinstate Monica May 24 '22 at 02:25
  • 1
    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`.) – Peter Cordes May 24 '22 at 02:27
  • @PeterCordes Huh, I didn't know 16-bit supported that. Also, it looks like `loopw` works as an alternative to `addr16 loop`. – Joseph Sible-Reinstate Monica May 24 '22 at 02:36
  • 1
    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. – Peter Cordes May 24 '22 at 02:39