Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

main function not linked to the binary #75

Open
klangner opened this issue Feb 9, 2017 · 7 comments
Open

main function not linked to the binary #75

klangner opened this issue Feb 9, 2017 · 7 comments

Comments

@klangner
Copy link

klangner commented Feb 9, 2017

Hello. I'm new to this low level stuff and Rust, but thanks to your very good book Discovery, I hope to learn it.

I try to follow this book, and everything was ok until I tried to set the break point on function main() (Chapter 5).
My problem is that the gdb says that there is no main() function in my code. And obj-dump confirms that there is no such function.
I guess that since there is no reference to this function it was simply omitted.

I would expect that the file stm32f3discovery.ld will contain declaration with the main() but there is only _init().

Here is the contents of my stm32f3discovery.ld:

MEMORY
{
  CCRAM : ORIGIN = 0x10000000, LENGTH = 8K
  FLASH : ORIGIN = 0x08000000, LENGTH = 256K
  RAM : ORIGIN = 0x20000000, LENGTH = 40K
}

ENTRY(_reset)

SECTIONS
{
  .text ORIGIN(FLASH) :
  {
    /* Vector table */
    LONG(ORIGIN(RAM) + LENGTH(RAM));
    LONG(_reset + 1);
    KEEP(*(.rodata._EXCEPTIONS));
    _eexceptions = .;
    /* Entry point: reset handler */
    _reset = .;
    *(.text._reset);

    *(.text.*);
    *(.rodata.*);
  } > FLASH
  /DISCARD/ :
  {
    *(.ARM.exidx.*)
    *(.bss.*)
    *(.data.*)
  }
}

/* HACK to make these symbols overrideable by _dependencies_ (they were
   already overridable by the top crate), we declare them as undefined
   (EXTERN) here. */
EXTERN(__aeabi_memclr4);
EXTERN(_default_exception_handler);
EXTERN(_init);

/* Exceptions */
PROVIDE(_nmi = _default_exception_handler);
PROVIDE(_hard_fault = _default_exception_handler);
PROVIDE(_memmanage_fault = _default_exception_handler);
PROVIDE(_bus_fault = _default_exception_handler);
PROVIDE(_usage_fault = _default_exception_handler);
PROVIDE(_svcall = _default_exception_handler);
PROVIDE(_pendsv = _default_exception_handler);
PROVIDE(_systick = _default_exception_handler);
ASSERT(_eexceptions - ORIGIN(FLASH) == 0x40, "exceptions not linked where expected");

If I add EXTERN(main); after _init, then main() is executed but _init() doesn't.
Shouldn't this script contain main() function?
Or any tips what I'm missing here?

My system: Ubuntu 16.10, Rust 1.17.0, board STM32F3Discovery.

Thank you for your great work!

@japaric
Copy link
Owner

japaric commented Feb 9, 2017

Your main has to be unmangled:

#[no_mangle]
pub fn main() -> ! {
    loop {}
}

or the linker will drop it. This is because the entry point, _reset, calls the main symbol. You should get a linker error if main doesn't have the no_mangle attribute though.

That being said, there's a bug where main doesn't make it to the final binary but you don't get a linker error. But that only happens with a certain type of main, when LTO is enabled and you are compiling in release mode. rust-lang/rust#39253 (not fixed, closed as duplicate)

If I add EXTERN(main); after _init, then main() is executed but _init() doesn't.
Shouldn't this script contain main() function?

That sounds weird. Maybe the functions are being inlined and that's why it seems that they are not being called. Maybe try adding #[inline(never)] to main. Are you testing all this in release mode? Maybe try the dev profile.

@klangner
Copy link
Author

klangner commented Feb 9, 2017

My main.rs is taken from the book:

#![no_std]
#![no_main]

extern crate pg;

#[inline(never)]
#[no_mangle]
pub fn main() -> ! {
    let y;
    let x = 42;
    y = x;

    loop {}
}

And I compile debug version.
Maybe something changed in the newest Rust version?

My whole project is at:
https://github.com/klangner/stm32f3discovery

But now I understand how main is called. So no need for ENTRY in *.ld file.

@klangner
Copy link
Author

klangner commented Feb 9, 2017

Also this is how the _reset function looks like:

08000040 <_reset>:
 8000040:	b580      	push	{r7, lr}
 8000042:	466f      	mov	r7, sp
 8000044:	b082      	sub	sp, #8
 8000046:	e7ff      	b.n	8000048 <_reset+0x8>
 8000048:	f000 f909 	bl	800025e <f3::delay::init>
 800004c:	e7ff      	b.n	800004e <_reset+0xe>
 800004e:	f000 f95f 	bl	8000310 <f3::led::init>
 8000052:	e7ff      	b.n	8000054 <_reset+0x14>
 8000054:	b002      	add	sp, #8
 8000056:	bd80      	pop	{r7, pc}
pub unsafe fn init() {
    f3::delay::init();
    f3::led::init();
}

Looks like _init was inlined, but there is no call to main (If I understand it correctly)

@japaric
Copy link
Owner

japaric commented Feb 10, 2017

Also this is how the _reset function looks like:

That does look like rust-lang/rust#39253 but I can't repro

$ git clone --depth 1 https://github.com/klangner/stm32f3discovery
$ cd stm32f3discovery
$ xargo build --target thumbv7em-none-eabihf
$ arm-none-eabi-objdump -Cd target/thumbv7em-none-eabihf/debug/stm32f3discovery
08000040 <_reset>:
 8000040:       b580            push    {r7, lr}
 8000042:       466f            mov     r7, sp
 8000044:       b082            sub     sp, #8
 8000046:       e7ff            b.n     8000048 <_reset+0x8>
 8000048:       f000 f811       bl      800006e <_init>
 800004c:       e7ff            b.n     800004e <_reset+0xe>
 800004e:       f000 f807       bl      8000060 <main>
 8000052:       e7ff            b.n     8000054 <_reset+0x14>
 8000054:       f640 1098       movw    r0, #2456       ; 0x998
 8000058:       f6c0 0000       movt    r0, #2048       ; 0x800
 800005c:       f000 fc6d       bl      800093a <core::panicking::panic::h61d607ef3390ba74>

With

$ git rev-parse HEAD
0905ba6762aff6c110c7dcd2a9d0014ce9c236bc

$ rustc -V
rustc 1.17.0-nightly (29dece1c8 2017-02-08)

@klangner
Copy link
Author

I'm not sure if it is related to this issue. I would rather guess that the problem is with the core library.

I can make the program running by putting all the code into init() function.
And this works:

#[export_name = "_init"]
pub fn init() {
    unsafe {
        f3::delay::init();
        f3::led::init();
    }

    loop {
        LEDS[0].on();
        LEDS[1].off();
        delay::ms(500);
        LEDS[0].off();
        LEDS[1].on();
        delay::ms(500);
    }
}

But if I add this declaration:

pub fn init() {
  ...
  let leds = LEDS.iter();
  ...
}

Then it doesn't (It is necessary to use iter(). The debugger doesn't event start in _init() function.

Maybe the problem is with arm toolchain?

arm-none-eabi-gcc --version
arm-none-eabi-gcc (GNU Tools for ARM Embedded Processors) 6.2.1 20161205 (release) [ARM/embedded-6-branch revision 243739]

Any ideas, how can I better debug this problem?

@japaric
Copy link
Owner

japaric commented Feb 18, 2017

@klangner are you using a mac? Does the gcc you are using come from the gcc-arm-embedded tap/cask? Someone reported (rust-embedded/discovery#34) that that gcc has some bug like the one you reported here. Could you try the gcc from the px4/px4 tap? (Sorry, I don't have the exact instructions to do that as I don't access to a mac)

@klangner
Copy link
Author

klangner commented Feb 19, 2017

No. I'm on Linux (Ubuntu).
Currently I'm following the blog http://hannobraun.de/embedded/ and learning about Rust and embedded development. So far so good. I hope to solve this problem as soon as I learn more about it.

But I will try to upgrade my GCC. It looks like this should help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants