Skip to content

copy_nonoverlapping optimizes to a __aeabi_memcpy function that recurses infinitely #31544

Closed
@japaric

Description

@japaric

on a custom target with no-compiler-rt: true.

This binary:

08000000 <_ZN10EXCEPTIONS20h109777d051950307UbaE>:
 8000000:       20002000        andcs   r2, r0, r0
 8000004:       08000009        stmdaeq r0, {r0, r3}

08000008 <__reset>:
 8000008:       b580            push    {r7, lr}
 800000a:       f240 0000       movw    r0, #0
 800000e:       f240 0100       movw    r1, #0
 8000012:       f2c2 0000       movt    r0, #8192       ; 0x2000
 8000016:       f2c2 0100       movt    r1, #8192       ; 0x2000
 800001a:       1a09            subs    r1, r1, r0
 800001c:       f021 0203       bic.w   r2, r1, #3
 8000020:       f240 0140       movw    r1, #64 ; 0x40
 8000024:       f6c0 0100       movt    r1, #2048       ; 0x800
 8000028:       f000 f806       bl      8000038 <__aeabi_memcpy4>
 800002c:       f240 0000       movw    r0, #0
 8000030:       f6c0 0000       movt    r0, #2048       ; 0x800
 8000034:       6800            ldr     r0, [r0, #0]
 8000036:       e7fe            b.n     8000036 <__reset+0x2e>

08000038 <__aeabi_memcpy4>:
 8000038:       f000 b800       b.w     800003c <__aeabi_memcpy>

0800003c <__aeabi_memcpy>:
 800003c:       e7fe            b.n     800003c <__aeabi_memcpy>

Was generated by this cargo project:

// src/main.rs
#![feature(core_intrinsics)]
#![feature(lang_items)]

#![no_std]

extern crate rlibc;

use core::{intrinsics, mem};

// Entry point
#[no_mangle]
pub unsafe extern "C" fn __reset() {
    init_data();

    // Make sure the compiler doesn't remove the EXCEPTIONS symbol
    intrinsics::volatile_load(&EXCEPTIONS[0]);

    loop {}
}

// Initialize the data section
unsafe fn init_data() {
    extern "C" {
        static __DATA_LOAD: u32;

        static mut __DATA_END: u32;
        static mut __DATA_START: u32;
    }

    let n = (&__DATA_END as *const _ as usize - &__DATA_START as *const _ as usize) /
            mem::size_of::<u32>();

    intrinsics::copy_nonoverlapping(&__DATA_LOAD, &mut __DATA_START, n);
}

// This is how compiler-rt defines this symbol
#[no_mangle]
pub unsafe extern "C" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, size: usize) {
    rlibc::memcpy(dest, src, size);
}

// This is how compiler-rt defines this symbol
#[no_mangle]
pub unsafe extern "C" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, size: usize) {
    rlibc::memcpy(dest, src, size);
}

// Stuff to build a place symbols in the addresses where the hardware expects them
extern "C" {
    fn __STACK_START();
}

#[link_section = ".exceptions"]
static EXCEPTIONS: [Option<unsafe extern "C" fn()>; 2] = [Some(__STACK_START), Some(::__reset)];

mod lang_items {
    #[lang = "eh_personality"]
    fn eh_personality() {}

    #[lang = "panic_fmt"]
    fn panic_fmt() {}

    // Unused, just to appease the compiler
    #[lang = "start"]
    fn start(_: *const u8, _: isize, _: *const *const u8) -> isize {
        0
    }
}

// Unused, just to appease the compiler
fn main() {}

thumbv7m-none-eabi.json

{
  "arch": "arm",
  "llvm-target": "thumbv7m-none-eabi",
  "os": "none",
  "target-endian": "little",
  "target-pointer-width": "32",

  "cpu": "cortex-m3",
  "executables": true,
  "morestack": false,
  "no-compiler-rt": true,
  "pre-link-args": [
    "-Tlayout.ld",
    "-Wl,--build-id=none",
    "-Wl,--gc-sections",
    "-mcpu=cortex-m3",
    "-mthumb",
    "-nostartfiles"
  ],
  "relocation-model": "static"
}
# Cargo.toml
[package]
authors = []
name = "bug"
version = "0.1.0"

[dependencies]
rlibc = { git = "https://github.com/hackndev/rlibc", branch = "zinc" }
rust-libcore = "0.0.3"
/* layout.ld */
MEMORY
{
    rom(RX)     : ORIGIN = 0x08000000, LENGTH = 128K
    ram(WAIL)   : ORIGIN = 0x20000000, LENGTH = 8K
}

ENTRY(__reset)

__DATA_LOAD = LOADADDR(.data);

SECTIONS
{
    .text : ALIGN(4)
    {
        KEEP(*(.exceptions))
        *(.text*)
    } > rom

    .data : ALIGN(4)
    {
      __DATA_START = .;
      *(.data*)
      . = ALIGN(4);
      __DATA_END = .;
    } > ram AT > rom

    /DISCARD/ :
    {
      *(.ARM.exidx*)
    }

    __STACK_START = ORIGIN(ram) + LENGTH(ram);
}

Version

rustc 1.8.0-nightly (75271d8f1 2016-02-09)

Workarounds

  • Define __aeabi_memcpy4 as a loop instead of using rlibc::memcpy then you can drop the rlibc dependency. But depending on how you write the definition you may end with infinite recursion again.
  • Remove the __aeabi_memcpy4 function and link to a cross compiled libcompiler-rt.a by changing no-compiler-rt to false. This is hard to do because one needs to patch rust-lang/compiler-rt to work with a specific custom target.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions