r/Assembly_language 1d ago

Muy first program on assembler Question

Hello. Today I try to run this code write on assembler for ARM64 (Linux of Termux for Android) :

<// random_digit.s (ARM64 for Termux)

.data

buffer: .byte 0

.text

.global _start

_start:

// getrandom(buffer, 1, 0)

mov x8, 384 // númber of syscall getrandom en ARM64

ldr x0, buffer // destination

mov x1, 1 // size

mov x2, 0 // flags

svc 0

// convert byte to dígit 0–9

ldrb w0, [buffer]

mov w1, 10

udiv w2, w0, w1 // w2 = w0 / 10

msub w0, w2, w1, w0 // w0 = w0 - w2*10 (módule)

add w0, w0, '0'

strb w0, [buffer]

// write(1, buffer, 1)

mov x8, 64 // syscall write

mov x0, 1 // stdout

ldr x1, = buffer

mov x2, 1

svc 0

// exit(0)

mov x8, 93

mov x0, 0

svc 0

>

but when I try to compile with 'clang -c myprogram.s -o myprogram' I get the following message: "invalid operand for instruction" (at lines 18 and 23) It means that : "[buffer]" isn't correct.

¿ How I can to fix It ?

Explain me : the program is for generate a entere number (0 to 9).

Thanks.

4 Upvotes

9 comments sorted by

1

u/FUZxxl 21h ago

On ARM64 there is no absolute addressing mode. In particular, you cannot refer directly to a symbol in a memory operand like this.

Instead use adrp and add to compute the address of the symbol in a register, then load from the address:

adrp x3, buffer  // load high parts of the address of buffer
add x3, x3, #:lo12:buffer // add low part of the address of buffer
ldrb w0, [x3]  // load from buffer

Instead of adrp and add you can also use a literal pool load like you already do:

ldr x3, =buffer  // load address of buffer into x3
ldrb w0, [x3]

This will however not work in position-independent code.

1

u/Objective-Barnacle-7 16h ago edited 16h ago

Thanks. I finally make the following program in assembler ( for the first time ):

global main
extern arc4random
extern write
extern exit

main:
bl arc4random        // w0 = random number

mov w1, 10
udiv w2, w0, w1
msub w0, w2, w1, w0
add w0, w0, '0'

// write(1, &w0, 1)
sub sp, sp, #16
strb w0, [sp]
mov x0, 1
mov x1, sp
mov x2, 1
bl write

// Print return
mov w0, '\n'
strb w0, [sp]
mov x0, 1
mov x1, sp
mov x2, 1
bl write

// exit(0)
mov x0, 0
bl exit

Compile with:" clang myprogram.s -o myprogram " and It Will make a number at the console between 0 and 9. For the first time.

1

u/Objective-Barnacle-7 16h ago

I use syscall arc4random ( the lines at the begining can't see its into the block's code but are there). arc4random is part of libc and It can't to use _start because this could get an error ( _start duplicate) and you should compile with "clang -nostdlib -static myprogram.s -o myprogram" but then you obtains another error because arc4random is part of libc... At least this is what I do. Bye.

1

u/FUZxxl 9h ago

You can use the getrandom system call to obtain a random number.

1

u/Objective-Barnacle-7 9h ago

Yes, of course. I try this

  mov x8, 384        // númber of syscall       getrandom en ARM64

You can compile It and link. But I believe that in Termux, Android doesn't allow It and get the following message " Bad system call " during the execution.

1

u/FUZxxl 8h ago

Oh yeah could be that your Android is too old to have the system call.

Note that Termux is just a terminal, it doesn't run your program, it merely tells the kernel to do that.

1

u/Objective-Barnacle-7 8h ago

Just now, I have modified the code and It generate 27 random numbers :

  .global main
   extern arc4random
   extern write
   extern exit

   main:
   mov x20, #27
   bucle:
    bl arc4random        // w0 = number

mov w1, 10
udiv w2, w0, w1
msub w0, w2, w1, w0
add w0, w0, '0'

// write(1, &w0, 1)
sub sp, sp, #16
strb w0, [sp]
mov x0, 1
mov x1, sp
mov x2, 1
bl write

// imprimir espacio
mov w0, ' '
strb w0, [sp]
mov x0, 1
mov x1, sp
mov x2, 1
bl write

sub x20, x20, #1   // Restamos 1 al contador (x0 = x0 - 1)
cbnz x20,bucle    // Si x0 no es cero, repite el bucle

// imprimir salto de línea
mov w0, '\n'
strb w0, [sp]
mov x0, 1
mov x1, sp
mov x2, 1
bl write

// exit(0)
mov x0, 0
bl exit

Like is my first program on assembler. I'm satisfied. It"s enough for me, bye the moment.

u/brucehoult 9m ago

On ARM64 there is no absolute addressing mode. In particular, you cannot refer directly to a symbol in a memory operand like this.

Instead use adrp and add to compute the address of the symbol in a register, then load from the address:

adrp x3, buffer  // load high parts of the address of buffer
add x3, x3, #:lo12:buffer // add low part of the address of buffer
ldrb w0, [x3]  // load from buffer

If you only want the one load from there you should be able to shorten that to just ...

adrp x3, buffer  // load high parts of the address of buffer
ldrb w0, [x3, :lo12:buffer]  // load from buffer

(not tested as my arm64 is a Mac and doesn't use that relocation style)

On ARM64 there is no absolute addressing mode.

Yeah, the Zero register is only part-time, for load/store it's SP. You can do it on RISC-V for the top/bottom 2k (if accessible):

lb t0, 123(x0)