1

I am trying to create a switch statement in assembly; however, I seem to always get stuck on the first case, no matter what the value is:

SECTION .data
    newLine    db  0xA,0xD
    NewLen     equ $- newLine

    nvalue     dw  2          ; nth number for case

    msg0       db  'a', 0xa 
    msg1       db  'b', 0xa 
    msg2       db  'c', 0xa  
    msg3       db  'd', 0xa 
    defaultMsg db  'e'

SECTION .text
    global  _start

    _start:
        mov eax, nvalue

        cmp eax, 0
        je  case0
        cmp eax, 1
        je  case1
        cmp eax, 2
        je  case2
        cmp eax, 3
        je  case3

        case0:
            mov  edx, 2
            mov  eax, 4
            mov  ebx, 1
            mov  ecx, msg0        
            mov  edx, 1        
            int  80h
            call printNL
            call quit
        case1:
            mov  edx, 2
            mov  eax, 4
            mov  ebx, 1
            mov  ecx, msg1        
            mov  edx, 1        
            int  80h
            call printNL
            call quit
        case2:
            mov  edx, 2
            mov  eax, 4
            mov  ebx, 1
            mov  ecx, msg2        
            mov  edx, 1        
            int  80h
            call printNL
            call quit
        case3: 
           mov  edx, 2
           mov  eax, 4
           mov  ebx, 1
           mov  ecx, msg3        
           mov  edx, 1        
           int  80h
           call printNL
           call quit

        mov  edx, 2
        mov  eax, 4
        mov  ebx, 1
        mov  ecx, defaultMsg        
        mov  edx, 1        
        int  80h
        call printNL
        call quit

    printNL:
        mov edx, NewLen
        mov ecx, newLine
        mov ebx, 1       
        mov eax, 4      
        int 80h

    quit:
        mov ebx, 0
        mov eax, 1
        int 80h
        ret

The string output is always 'a' (case0 for when the nvalue variable is 0). Why is it doing this when nvalue is 2?

thetipsyhacker
  • 1,402
  • 4
  • 18
  • 39
  • 3
    You want `mov eax, [nvalue]` See [section 2.2.2 NASM Requires Square Brackets For Memory References in the nasm manual](https://www.nasm.us/xdoc/2.11.08/html/nasmdoc2.html#section-2.2.2) You were loading the address not the value. Also you used the wrong directive, you want `dd` for a double word. Alternatively use `movzx eax, word [nvalue]`. – Jester Oct 01 '20 at 18:13
  • Thank you very much @Jester ! That helps me understand it better. – thetipsyhacker Oct 01 '20 at 18:22
  • `call quit` is very confusing! Better write `jmp quit`. – Sep Roland Oct 04 '20 at 20:32
  • The block where you print *defaultMsg* should go directly above the label `case0:`. In assembly programming, indenting the text is important for readability, but it doesn't say anything about logical structures like switches. – Sep Roland Oct 04 '20 at 20:36

2 Answers2

4
        mov eax, nvalue

        cmp eax, 0
        je  case0
        cmp eax, 1
        je  case1
        cmp eax, 2
        je  case2
        cmp eax, 3
        je  case3

        case0:

What this code does is

  1. Load the address of nvalue into eax.
  2. Compare this address with 0, 1, 2 and 3.
  3. If the comparison with 1, 2 or 3 succeeds, jump away to corresponding labels.
  4. Otherwise, jump or fall through to case0.

What you actually want, first of all, is to read the value of nvalue into eax. And this is done by

mov eax, [nvalue]

if you had nvalue defined with dd. If you leave it as it's now, with dw, then the loading could be like

movzx eax, word [nvalue]

And the second point, you may want to add a jump away before the case0 label, if you don't want to fall through to it when all comparisons fail.
Alternatively place the block where you print the defaultMsg, between je case3 ... case0:. This way you shave off the extra jmp.

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
Ruslan
  • 18,162
  • 8
  • 67
  • 136
  • Thanks @Ruslan . What do you mean by "jump away"? Are you referring to the 'default' case? If so, I thought my default was where I was printing defaultMsg outside of all my 'case' functions. – thetipsyhacker Oct 01 '20 at 18:27
  • @SJCypher your default is when `je case3` branch is not taken (`ZF==0`). If it's not taken, you end up executing the `case0` code. – Ruslan Oct 01 '20 at 18:28
  • (off topic: your answer on [Unable to set the lowest byte in a register x86-64?](https://stackoverflow.com/q/64115162) looks right; what was wrong with it that made you decide to delete it? You can reply to my comment on that question, instead of this comment thread) – Peter Cordes Oct 06 '20 at 22:14
  • @PeterCordes I've found that it's not quite right to say that `*L` is something strange: first, yasm and fasm, for example, appear to understand `spl` but not `spb`. And if I do remove this part, what remains will just talk about convenience variables, which seems rather obvious from the comments. In any case that answer needs rework before undeleting. – Ruslan Oct 06 '20 at 22:18
  • See my comments under that question with links for more history of `l` (AMD) vs. `b` (Intel) suffixes for r8..r15. The original-8 registers always use `l`, for consistency with `al`/`bl`/... But yes it's especially inconsistent and conflicting with AT&T syntax's convention of `l` = long 32-bit operand-size for mnemonics. – Peter Cordes Oct 06 '20 at 22:21
-3
replace:
    nvalue     dw  2          ; nth number for case
with:
    nvalue     dd  2          ; nth number for case

dos asm is quirky.

Also, you might want to add a default case -- that is why it is falling through.

mevets
  • 10,070
  • 1
  • 21
  • 33
  • Thank you. I thought my default case was the code block printing the "defaultMsg" outside of the 'case' functions. Is that not the case? – thetipsyhacker Oct 01 '20 at 18:16
  • 1
    It's not DOS, it's Linux, judging by `int 0x80`. – Ruslan Oct 01 '20 at 18:17
  • 'dos asm' the assembler from dos. – mevets Oct 01 '20 at 20:11
  • `nasm` isn't "the assembler from DOS". It was originally developed as a portable assembler that would run well on non-DOS machines, to make it easy to develop bootloaders like syslinux and isolinux on GNU/Linux machines. https://nasm.us/ – Peter Cordes Oct 05 '20 at 02:41
  • It uses that ambiguous dos format, which makes it an assembler from dos; worse, it redefines it so that it enters yet a third syntax. The OP used a `mov symbol, eax`, which a dos assembler would make a load from memory, nasm would turn into what a dos asm would call `lea`; only as would correctly say "syntax error". So, right, not technically dos, but still dos. – mevets Oct 06 '20 at 02:21