Can i use binary to write integer constants in assembly?

14,154

You're writing constants in decimal. If you want the digits to be interpreted as base-2, you need to tell the assembler about it. It's not going to do that just because they happen to all be 0 or 1.

3.4.1 Numeric Constants in the NASM online manual (first google hit for: nasm binary constant):

Some examples (all producing exactly the same code):

    mov     ax,200          ; decimal 
    mov     ax,0200         ; still decimal 
    mov     ax,0200d        ; explicitly decimal 
    mov     ax,0d200        ; also decimal 
    mov     ax,0c8h         ; hex 
    mov     ax,$0c8         ; hex again: the 0 is required 
    mov     ax,0xc8         ; hex yet again 
    mov     ax,0hc8         ; still hex 
    mov     ax,310q         ; octal 
    mov     ax,310o         ; octal again 
    mov     ax,0o310        ; octal yet again 
    mov     ax,0q310        ; octal yet again 
    mov     ax,11001000b    ; binary 
    mov     ax,1100_1000b   ; same binary constant 
    mov     ax,1100_1000y   ; same binary constant once more 
    mov     ax,0b1100_1000  ; same binary constant yet again 
    mov     ax,0y1100_1000  ; same binary constant yet again

Obviously you can use these prefixes or suffixes on constants anywhere, not just immediate operands.

So yes, you can use binary. Note that the code in your question used a one-bit constant, not a one-byte constant, for the value stored in one. one = 1, and two = 2, but four = 2^3 + 0 + 2^1 + 1 = 11(decimal).

eight is similarly strangely defined. It should be eight = 1000b.

All power-of-two integers only have a single bit set in their binary representation, just like all power-of-10 numbers have a single 1 in their decimal representation.

Maybe those names were just the widths, not the values?


mov rax, [one] is an 8-byte load, spanning the db, dw, and dd, and the first byte of the dq.

The only form of the mov instruction that does any sign-extension is mov r64, imm32, and that sign-extends the immediate, not a memory source. Both operands for mov are always the same size (except for the imm32 case); it unfortunately doesn't even have a sign-extended imm8 form like add r/m64, imm8 does.

If you want to load from memory with sign-extension, look up movsx in the insn ref manual. (linked from the info wiki.) e.g. movsx rax, byte [mem]. In your case, zero-extending would give the same result: movzx eax, byte [one] to zero-extend into RAX. (Generally prefer zero-extension; on some CPUs it's slightly more efficient.)

(Also, you normally want default rel so [one] is a RIP-relative addressing mode.)

Share:
14,154
Nasmarr
Author by

Nasmarr

Updated on June 18, 2022

Comments

  • Nasmarr
    Nasmarr almost 2 years

    i have an assignment that asks to define 4 integers, each of a different byte length (1, 2, 4, 8)

    would this code work?

           segment .data
    one    db      1
    two    dw      01
    four   dd      1011
    eight  dq      01101110
    
           global _start
    _start:
    mov    rax, [one]    ;
    mov    rbx, [two]    ;
    

    im also curious if i can safely store these values into registers to be used for addition in the future. I'm supposed to use sign extension for the shorter values, but could use some direction