3

I am trying to compile a Rust program for a Raspberry Pi. I am under the impression that the start address needs to be 0x8000, so I am using a custom linker script to lay out the program to follow this requirement:

SECTIONS
{
  .text 0x8000 : {
    *(.text)
  }

  .data : {
    *(.data)
  }
}

I specify this in the architecture file aarch64-unknown-none.json:

{
  "arch": "aarch64",
  "data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
  "disable-redzone": true,
  "executables": true,
  "features": "+strict-align,+neon,+fp-armv8",
  "linker": "rust-lld",
  "linker-flavor": "ld.lld",
  "pre-link-args": {
    "ld.lld": [
      "-Taarch64-raspi3.ld"
    ]
  },
  "llvm-target": "aarch64-unknown-none",
  "max-atomic-width": 128,
  "panic-strategy": "abort",
  "relocation-model": "static",
  "target-pointer-width": "64",
  "unsupported-abis": [
    "stdcall",
    "stdcall-unwind",
    "fastcall",
    "vectorcall",
    "thiscall",
    "thiscall-unwind",
    "win64",
    "sysv64"
  ]
}

I build using the cargo build -Zbuild-std --features=raspi3 --target=aarch64-unknown-none.json --release command.

Here is my main.rs:

#![cfg_attr(not(test), no_std)]
#![cfg_attr(not(test), no_main)]
#![feature(global_asm)]
#![feature(asm)]
#![feature(naked_functions)]

#[cfg(not(test))]
global_asm!(include_str!("platform/raspi3/start.s"));

mod aarch64;
mod panic;
mod platform;

Here is start.s:

.section .init
.global _start

.equ BASE,  0x3f200000 //Base address
.equ GPFSEL2, 0x08          //FSEL2 register offset 
.equ GPSET0,  0x1c          //GPSET0 register offset
.equ GPCLR0,0x28            //GPCLR0 register offset
.equ SET_BIT3,   0x08       //sets bit three b1000      
.equ SET_BIT21,  0x200000   //sets bit 21
.equ COUNTER, 0xf0000

_start:
    ldr x0, =BASE
    ldr x1, =SET_BIT3
    str x1, [x0, #GPFSEL2]
    ldr x1, =SET_BIT21
    str x1, [x0, #GPSET0]
    b _start

When I compile it, it places the start block at 0x0 as follows:

0000000000000000 <_start>:
   0:   d2a7e400        mov     x0, #0x3f200000                 // #1059061760
   4:   d2800101        mov     x1, #0x8                        // #8
   8:   f9000401        str     x1, [x0, #8]
   c:   d2a00401        mov     x1, #0x200000                   // #2097152
  10:   f801c001        stur    x1, [x0, #28]
  14:   17fffffb        b       0 <_start>

Is there a reason that this is happening?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Someone
  • 800
  • 1
  • 7
  • 25

1 Answers1

2

When you write:

.text 0x8000 : {
    *(.text)
  }

you are telling the linker to set up the excutable .text section at address 0x8000, by concatenating the .text sections from every compilation module (*).

But then, in your assembly, the _start function is defined in the .section .init, that is not mentioned anywhere in the linker script. I'm not sure of what happens exactly with sections that are not mentioned in the linker script, but I'm pretty sure it is a bad idea to rely on that.

You probably want your .init section(s) to be at the start of the executable .text section:

  .text 0x8000 : {
    *(.init) /* _start */
    *(.text)
  }

NOTE: AFAIK, Rust does not emit all the code into a big .text section, but it creates a lot smaller .text.name_of_the_thing sections. You'll probably want to link them all of them together so:

  .text 0x8000 : {
    *(.init) /* _start */
    *(.text)
    *(.text.*)
  }
rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • I think sections that aren't mentioned don't become part of the linker output at all. – Peter Cordes Jul 26 '21 at 23:32
  • @PeterCordes: That's what I thought, but the OP does get `_start` into the executable be without mentioning its section, and I reproduced it. It ended up in a `.init` section in the exe. My guess is that unmentioned sections are copied to an output section of the same name. But in what order? – rodrigo Jul 27 '21 at 00:09
  • I thought I remembered something like this coming up in other Q&As, but probably I'm misremembering what was written, or got the wrong idea somewhere. – Peter Cordes Jul 27 '21 at 00:35
  • @PeterCordes: From `info ld` that I guess it applies equally if you use a bogus `SECTIONS` (emphasis mine): _"If you do not use a `SECTIONS` command in your linker script, the linker will place each input section into **an identically named output section in the order that the sections are first encountered in the input files**. If all input sections are present in the first file, for example, the order of sections in the output file will match the order in the first input file. **The first section will be at address zero**."_ – rodrigo Jul 27 '21 at 07:17