2

I'm trying to learn ARM64. I'm assembling on the Apple M1.

I'm trying to allocate memory I can write to. I keep receiving the following error:

ld: Absolute addressing not allowed in arm64 code but used in '_main' referencing 'foo'

My program is very simple:

// foo.s
.global _main
.align 2

_main:
  ldr x0, =foo

.data
foo: .zero 8

I'm using this script to compile it:

#!/bin/bash

as foo.s -o foo.o &&                               \
                                                   \
ld foo.o -o foo                                    \
   -arch arm64                                     \
   -syslibroot `xcrun -sdk macosx --show-sdk-path` \
   -lSystem

After some googling, I tried setting -no_pie for ld but that results in:

ld: warning: -no_pie ignored for arm64

I'm not really sure what's going on.

Thanks

Update: There's a SO question here that explains the problem.

I applied that fix and wrote this quick program to test that it works:

.global _main
.align 2

_main:
  // Set x0 to the memory address of foo.
  adrp x0, foo@PAGE
  add x0, x0, foo@PAGEOFF

  // Store 123 in foo.
  mov x1, 123
  str x1, [x0]

  // Load the contents of foo into x2.
  ldr x2, [x0]

  // Exit with a status code set to foo.
  mov x0, x2
  mov x16, 1
  svc 0

.data
foo: .zero 8

It returns with an exit status of 123 as I'd expect.

Chris
  • 1,501
  • 17
  • 32
  • And don't forget `.text` before you start defining `_main`. It may be the default, but it will save you from breakage if you decide to move your data to the top of the file. – Nate Eldredge Feb 12 '21 at 23:19
  • Thanks, the answer to that other SO question has done the trick! I'll be sure to add a `.text` to my program as you suggest! – Chris Feb 12 '21 at 23:22

1 Answers1

1

You allocated the memory just fine with .zero in the .data section. Now you just need to load its address in order to access it.

It's better to write position-independent code than to try to disable it. So instead of trying to load absolute addresses, access them relative to the program counter.

In a program of moderate size (less than a megabyte or so of code plus static data), you can load the address of foo into x0 with

adr x0, foo

The adr instruction adds an immediate constant to the value of the program counter pc, and leaves the result in the destination register. The assembler and linker can determine the difference between the address of the adr instruction and the address of foo, and encode that difference as the immediate of the adr instruction.

For larger programs, in which the difference in addresses may be up to 4 GB or so, you use a combination of adrp to get the high bits, and add or a load/store with offset. See What are the semantics of ADRP and ADRL instructions in ARM assembly?

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
  • Thanks Nate, that's really helpful. However, when I make that change I then get this error: 'foo.s:5:3: error: unknown AArch64 fixup kind!'. It's as though it can't find that label name anymore? – Chris Feb 12 '21 at 23:02
  • Oh, it appears from https://stackoverflow.com/questions/65351533/apple-clang12-llvm-unknown-aarch64-fixup-kind that on MacOS you have to use the "larger program" technique with `adrp` in all cases. I think that question may be a duplicate of yours. – Nate Eldredge Feb 12 '21 at 23:09
  • Thanks, that other SO post has worked. – Chris Feb 12 '21 at 23:24