Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can i use binary to write integer constants in assembly?

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

like image 903
Nasmarr Avatar asked Dec 03 '15 03:12

Nasmarr


1 Answers

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

like image 113
Peter Cordes Avatar answered Oct 13 '22 05:10

Peter Cordes