Skip to content

copy_nonoverlapping optimizes to a __aeabi_memcpy function that recurses infinitely #31544

@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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions