AArch64 ASM / Custom Sections and Common Variables

What is the proper way to have a variable common between two custom-defined sections?

Example:

.global foo1
.section .text.foo1, “ax”
foo1:
ldr w0, FooValue
ret

.global foo2
.section .text.foo2, “ax”
foo2:
ldr w0, FooValue
ret

FooValue: .word 0x00

This generates “unsupported relocation type: fixup_aarch64_ldr_pcrel_imm19”. If I comment out the first ldr line, it builds, as FooValue is part of .text.foo2.

If I define FooValue twice, once for each section it complains it’s already defined.

Joel

This is with lld-lnk -target aarch64-unknown-windows.

What target (in particular OS, object file format) are you trying to assemble for? Your example assembles without error for me with this command line:
clang --target=aarch64-none-eabi -c test.s -o test.o

That is generating ELF output, it’s possible that other formats don’t have the necessary relocations to represent the first LDR instruction, or LLVM doesn’t know how to emit them.

It’s also worth noting that a single LDR instruction only has a range of ±1MiB, which might not be what you want. I often find the easiest way to find reasonable assembly sequences is to compile a C file which does what you want and look at the assembly output. For example, with this C file:

long FooValue = 0x0;

__attribute((section(".text.foo1")))
long foo1() {
return FooValue;
}

__attribute((section(".text.foo2")))
long foo2() {
return FooValue;
}

clang emits this assembly:

.text
.file “test2.c”
.section .text.foo1,“ax”,@progbits
.globl foo1 // – Begin function foo1
.p2align 2
.type foo1,@function
foo1: // @foo1
// %bb.0: // %entry
adrp x8, FooValue
ldr x0, [x8, :lo12:FooValue]
ret
.Lfunc_end0:
.size foo1, .Lfunc_end0-foo1
// – End function
.section .text.foo2,“ax”,@progbits
.globl foo2 // – Begin function foo2
.p2align 2
.type foo2,@function
foo2: // @foo2
// %bb.0: // %entry
adrp x8, FooValue
ldr x0, [x8, :lo12:FooValue]
ret
.Lfunc_end1:
.size foo2, .Lfunc_end1-foo2
// – End function
.type FooValue,@object // @FooValue
.bss
.globl FooValue
.p2align 3
FooValue:
.xword 0 // 0x0
.size FooValue, 8

.ident “clang version 10.0.0 (git@github.com:llvm/llvm-project.git 36937ec7fb8e20b81adbac40bd48c6ed7ac6df61)”
.section “.note.GNU-stack”,"",@progbits
.addrsig

Note the use of the ADRP/LDR pair of instructions, which has a range of ±4GiB.

Oliver

Hi Joel,

This generates "unsupported relocation type: fixup_aarch64_ldr_pcrel_imm19". If I comment out the first ldr line, it builds, as FooValue is part of .text.foo2.

To reference a symbol across sections like this, you'd need to add a
relocation to the object file, but some formats (MachO I know) have a
ridiculously small number of permitted relocations and don't have room
for for pc-relative load relocations. I think you're probably hitting
that issue.

You've got two options:

1. Reference FooValue in a way that does have relocations. For example
(on MachO, I'm afraid I don't know the syntax for COFF, and it should
just be working anyway for ELF):

    adrp x0, FooValue@PAGE
    ldr w0, [x0, FooValue@PAGEOFFSET]

2. Use a local symbol with a different name each time (starting with L
on MachO), and defined within the section that references it
(actually, probably before the next global symbol if you're using
.subsections_via_symbols, which you should be):

    .section .text.foo1
foo1:
   ldr w0, LFooValue.foo1
   ret
LFooValue.foo1:
  .word 0

    .section .text.foo2
foo2:
   ldr w0, LFooValue.foo2
   ret
LFooValue.foo2:
  .word 0

Cheers.

Tim.

Hi Oliver,

Great idea. I’ll take this approach.

Thanks,
Joel

Thanks Tim!