Search code examples
linuxassemblyarm64

Storing the low byte of an integer register with STR?


I tried to write some AArch64 ASM code for printing a number to the terminal in decimal. The code is supposed to divide the input number by 10000, store the result in a buffer, multiply it by 10000 again and then subtract the result from the original number to remove the first digit of the number. This then repeats for 1000, 100, 10 and at last 1. This should calculate the BCD representation of the number and store it in the buffer.

When debugging the code in gdb, the calculation seems to run perfectly, but after the str instruction, which is supposed to put the first digit into the buffer is run, the value in the buffer is still 0.

  .section .data
    BCDBuffer:
    .space 5 //Buffer of size 5
    BCDBufferLen = . -  BCDBuffer
    .section .text
    .global _start
    _start:
    ldr x1, =BCDBuffer
    mov x0, #65535
    //first compute BCD
    //Ill do this for 16 Bit numbers, so 65535 is largest number (5 digits)
    //Ill assume the input is in register w0 and the output ptr in register 1
    mov x4, #10000
    udiv w3, w0, w4
    str b3, [x1]
    umull x3, w3, w4
    sub w0, w0, w3
    add x1, x1,  #1
    
    mov x4, #1000
    udiv w3, w0, w4
    str b3, [x1]
    umull x3, w3, w4
    sub w0, w0 , w3
    add x1, x1,  #1
    
    mov x4, #100
    udiv w3, w0, w4
    str b3, [x1]
    umull x3, w3, w4
    sub w0, w0, w3
    add x1, x1, #1
    
    mov x4, #10
    udiv w3, w0, w4
    str b3, [x1]
    umull x3, w3, w4
    sub w0, w0, w3
    add x1, x1, #1
    
    str b0, [x1]
    sub x1, x1, #4
    
    //now there should be a bcd version of the number at address x1.
    //Numbers in ascii start at 48, so if I just increment all of these by 48, then Ill get a string with the chars
    asciistuff:
    ldr b0, [x1]
    add w0, w0, #48
    str b0, [x1], #1
    
    ldr b0, [x1]
    add w0, w0, #48
    str b0, [x1], #1
    
    ldr b0, [x1]
    add w0, w0, #48
    str b0, [x1], #1
    
    ldr b0, [x1]
    add w0, w0, #48
    str b0, [x1], #1
    
    ldr b0, [x1]
    add w0, w0, #48
    str b0, [x1]
    sub x1, x1, #3
    
    
    mov x0, #0 //STDOUT
    //register 1 already has the right ptr
    mov x2, #5 //Buffer Length
    mov w8, #64 //Write syscall
    svc #0
    mov x0, #0
    mov w8, #93
    svc #0


Solution

  • This instruction:

    str b3, [x1]
    

    does not do what you expect it to do. This is a floating-point store instruction, storing the low byte of floating-point register 3 (aka b3, h3, s3, d3, q3, v3) to memory at the address indicated in x1. As you have not set floating-point register 3 to anything meaningful before, this instruction does not store any meaningful value to memory.

    To instead store the low byte of register w3 / x3, use a strb (store byte) instruction:

    strb w3, [x1]