Linking a 64 bit Kernel - c++

Hi All I have been trying to link my assembly code to a C++ file so I can fall my function kMain from assembly and When I link it with this script :
ENTRY(_Start)
SECTIONS
{
. = 0x2000;
.text : AT(ADDR(.text) - 0x2000)
{
_code = .;
*(.text)
*(.rodata*)
. = ALIGN(4096);
}
.data : AT(ADDR(.data) - 0x2000)
{
_data = .;
*(.data)
. = ALIGN(4096);
}
.eh_frame : AT(ADDR(.eh_frame) - 0x2000)
{
_ehframe = .;
*(.eh_frame)
. = ALIGN(4096);
}
.bss : AT(ADDR(.bss) - 0x2000)
{
_bss = .;
*(.bss)
/*
* You usually need to include generated COMMON symbols
* under kernel BSS section or use gcc's -fno-common
*/
*(COMMON)
. = ALIGN(4096);
}
_end = .;
/DISCARD/ :
{
*(.comment)
}
}
I get a warning saying : x86_64-elf-ld: warning: cannot find entry symbol _Start; defaulting to 0000000000002000
But in my Assembly Code I have this at the start:
[BITS 16]
_Start:
Any Ideas as to why its not linking Correctly??
EDIT: It works now With this declared:
global _Start:
_Start:
But It won't load the program at the adress 0x2000
I use a batch program to compile/assemble, format and link my OS here it is:
nasm Stage1.asm -o Stage1.bin
nasm -f elf64 Stage2.asm -o Stage2.o
x86_64-elf-g++ -ffreestanding -mcmodel=large -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow -c -o kernel.o kernel.cpp
x86_64-elf-ld -T linkerscript.ld -o MyOS.bin Stage2.o kernel.o -nostdlib
copy Stage1.bin Root
copy MyOS.bin Root
mkisofs -b Stage1.bin -no-emul-boot -boot-info-table -o BootLoader.iso ./Root
If you wan't to see all of the source code it is here:
https://github.com/AnonymousUser1337/Anmu

You probably have to declare the _Start label as global using some kind of assembler directive (e.g. global).

Related

Undefined reference to _fini and __dso_handle when compiling c++ for arm cortex M3

I am trying to compile the c++ code for arm cortex-m3. When I use static variable of any class, which has custom destructors (like std::function<> for example), I get the following errors:
/Applications/ARM/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld: CMakeFiles/app.dir/src/acc_lis.cpp.obj: in function `unsigned char* std::__copy_move<false, true, std::random_access_iterator_tag>::__copy_m<unsigned char>(unsigned char const*, unsigned char const*, unsigned char*)':
/Applications/ARM/arm-none-eabi/include/c++/10.3.1/bits/stl_algobase.h:426: undefined reference to `__dso_handle'
/Applications/ARM/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld: /Applications/ARM/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/thumb/v7-m/nofp/libg.a(lib_a-fini.o): in function `__libc_fini_array':
fini.c:(.text.__libc_fini_array+0x20): undefined reference to `_fini'
/Applications/ARM/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld: app.elf: hidden symbol `__dso_handle' isn't defined
/Applications/ARM/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld: final link failed: bad value
From what I read, the problem is when c++ is trying to call the destructors after calling exit(), (which I am not calling manually). __dso_handle can be solved by adding -fno-use-cxa-atexit flag, but I have no idea what to do with _fini symbol.
Compiler/Linker flags:
set(CMAKE_C_FLAGS "-mcpu=cortex-m3 -mthumb -std=gnu11 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections")
set(CMAKE_C_FLAGS_RELEASE "-Os")
set(CMAKE_C_FLAGS_DEBUG "-g -Og -fno-move-loop-invariants")
set(CMAKE_CXX_FLAGS "-mcpu=cortex-m3 -mthumb -std=c++11 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -fno-exceptions")
set(CMAKE_CXX_FLAGS_RELEASE "-Os")
set(CMAKE_CXX_FLAGS_DEBUG "-g -Og -fno-move-loop-invariants")
set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> -Wl,--start-group <OBJECTS> <LINK_LIBRARIES> -Wl,--end-group -o <TARGET>")
set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> -Wl,--start-group <OBJECTS> <LINK_LIBRARIES> -Wl,--end-group -o <TARGET>")
set(CMAKE_EXE_LINKER_FLAGS "-nostartfiles -Xlinker --gc-sections -Xlinker --sort-section -Xlinker alignment --specs=nosys.specs")
SET(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp")
SET(CMAKE_ASM_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
SET(CMAKE_ASM_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
Linker script (sections part):
SECTIONS
{
.text :
{
. = ALIGN(4);
KEEP(*(.interrupt_vector))
KEEP(*(.reset))
. = ALIGN(4);
*(.rodata.boot.*)
/* Pre-initialization Code */
. = ALIGN(4);
PROVIDE_HIDDEN (__preinit_array_start__ = .);
/* System initialization and the platform initialization (if present)
* should be first */
KEEP(*(.preinit_array_sysinit .preinit_array_sysinit.*))
KEEP(*(.preinit_array_platform .preinit_array_platform.*))
/* Pre-initialization functions (to be executed before C++
* constructors are run) */
KEEP(*(.preinit_array .preinit_array.*))
PROVIDE_HIDDEN (__preinit_array_end__ = .);
/* Initialization Code */
. = ALIGN(4);
PROVIDE_HIDDEN (__init_array_start__ = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE_HIDDEN (__init_array_end__ = .);
. = ALIGN(4);
*(.text .text.*) /* all remaining code */
*(.rodata .rodata.*) /* read-only data (constants) */
. = ALIGN(4);
__dsp_start__ = . ;
KEEP(*(.dsp .dsp.*)) /* all remaining DSP code */
__dsp_end__ = . ;
. = ALIGN(4);
} >FLASH
.ARM.exidx :
{
PROVIDE_HIDDEN (__exidx_start = .);
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
PROVIDE_HIDDEN (__exidx_end = .);
} >FLASH
. = ALIGN(4);
__data_init__ = .;
/* Place the SystemClock variable needed for CMSIS in a place that is
* compatible with the ROM's placement of this variable so that the
* variable can be used by CMSIS and the ROM's flash write libary */
.systemclock (NOLOAD) :
{
. = ALIGN(4);
KEEP(*(.systemclock))
} > DRAM
.data : AT ( __data_init__ )
{
. = ALIGN(4);
/* This is used by the startup code to initialize the .data section */
__data_start__ = . ;
*(.data_begin .data_begin.*)
*(.data .data.*)
*(.data_end .data_end.*)
/* Place sleep and wakeup routines in retention RAM
* Wakeup_From_Sleep_Application_asm has to followed directly by
* Wakeup_From_Sleep_Application */
*(.app_wakeup_asm)
KEEP(*(.app_wakeup))
KEEP(*(.sys_powermodes_wakeup_2mbps))
. = ALIGN(4);
/* This is used by the startup code to initialize the .data section */
__data_end__ = . ;
} >DRAM
.bss (NOLOAD) :
{
. = ALIGN(4);
__bss_start__ = .;
*(.bss_begin .bss_begin.*)
*(.bss .bss.*)
*(COMMON)
*(.bss_end .bss_end.*)
. = ALIGN(4);
__bss_end__ = .;
} >DRAM
.noinit (NOLOAD) :
{
. = ALIGN(4);
__noinit_start__ = .;
*(.noinit .noinit.*)
. = ALIGN(4) ;
__noinit_end__ = .;
} > DRAM
/* Check if there is enough space to allocate the main stack */
._stack (NOLOAD) :
{
. = ALIGN(4);
. = . + __Main_Stack_Size ;
. = ALIGN(4);
} >DRAM
. = __data_init__ + (__data_end__ - __data_start__);
PROVIDE(__flash_end__ = ALIGN(2048));
PROVIDE(__code_size = __flash_end__ - ORIGIN(FLASH));
}
Based on the libc source for initfini.c, _fini and _init are used for module initialization/deinitialization respectively. As the embedded code is not supposed to exit from the main, __libc_fini_array is not called which in turn does not call _fini(). Unfortunately, parts of stl calls exit() which is defined as:
uint8_t i;
for (i = 0; i < atexit_count; i++) {
atexit_funcs[i]();
}
__libc_fini_array();
_exit(return_code);
restarting the whole problem. When using nosys.specs, there is no _fini function defined, but we can define your own to fix this.
/* Make sure you have C linkage when defining in c++ file */
extern "C"
void _fini()
{
/* Either leave empty, or infinite loop here */
while (true)
__asm volatile ("NOP");
}
Furthermore need to provide __fini_array_start and __fini_array_end in a linker script for __libc_fini_array, but that's all there is to it.
Please note that we can skip this problem entirely while lazy-initializing the object by calling operator new instead if we have support for the dynamic allocation, or use std::aligned_storage and placement new to avoid calling destructors alltogether.

How to debug cross-compiled QEMU program with GDB?

I'm having trouble debugging a simple program running in QEMU with GDB. GDB seems unable to find where I am in the program (in that it always displays ?? as my current location), and it never hits any breakpoint I set.
In one terminal, I run QEMU:
$ cat add.c
int main() {
int x = 9;
int v = 1;
while (1) {
int q = x + v;
}
return 0;
}
$ riscv64-unknown-elf-gcc add.c -g
$ qemu-system-riscv64 -gdb tcp::1234 -drive file=a.out,format=raw
And in another terminal, I run GDB:
$ riscv64-unknown-elf-gdb a.out
GNU gdb (GDB) 8.2.90.20190228-git
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "--host=x86_64-apple-darwin17.7.0 --target=riscv64-unknown-elf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a.out...
(gdb) target remote :1234
Remote debugging using :1234
0x0000000000000000 in ?? ()
(gdb) list
1 int main() {
2 int x = 9;
3 int v = 1;
4 while (1) {
5 int q = x + v;
6 }
7 return 0;
8 }
(gdb) b main
Breakpoint 1 at 0x1018e: file add.c, line 2.
(gdb) b 5
Breakpoint 2 at 0x1019a: file add.c, line 5.
(gdb) b _start
Breakpoint 3 at 0x10114
(gdb) b 4
Breakpoint 4 at 0x101a8: file add.c, line 4.
(gdb) c
Continuing.
I never hit a breakpoint, even though the program should be looping infinitely. It seems odd that it's displaying 0x0000000000000000 in ?? ()...but maybe that's okay?
What am I doing wrong here? How can I step through this program?
I think you are missing a linker script and some startup code - disclaimer: I am a newcomer to riscv.
You will find a lot of information on those two topics on the Internet, but you basically need to specify where your program will be located in RAM, to establish a stack and initialize the frame pointer:
This is required if you want to be able to call functions and declare automatic C variables like a, b, c in your program.
I used the Windows toolchain from Kendryte for the purpose of this example (the Linux version is available here), and a Windows version of qemu retrieved here.
1) Linker script: the example uses a slightly modified example of the default linker script used by riscv64-unknown-elf-ld:
riscv64-unknown-elf-ld --verbose > riscv64-virt.ld
Edit riscv64-virt.ld, and keep only the lines delimited by:
==================================================
Add a description for the memory layout of the qemu-system-riscv64 virt machine:
OUTPUT_ARCH(riscv)
MEMORY
{
/* qemu-system-risc64 virt machine */
RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 128M
}
ENTRY(_start)
Use ORIGIN(RAM) and LENGTH(RAM) instead of hard-coded values, and provide a __stack_top symbol:
PROVIDE (__executable_start = SEGMENT_START("text-segment", ORIGIN(RAM))); . = SEGMENT_START("text-segment", ORIGIN(RAM)) + SIZEOF_HEADERS;
PROVIDE(__stack_top = ORIGIN(RAM) + LENGTH(RAM));
By the way, there are multiple ways of learning the memory layout of a qemu-system target machine, but I usually look at its Device Tree file:
qemu-system-riscv64 -machine virt -machine dumpdtb=riscv64-virt.dtb
dtc -I dtb -O dts -o riscv-virt.dts riscv-virt.dtb
The section describing the memory tells us it starts at 0x80000000:
memory#80000000 {
device_type = "memory";
reg = <0x0 0x80000000 0x0 0x8000000>;
};
riscv64-virt.ld:
/* Script for -z combreloc: combine and sort reloc sections */
/* Copyright (C) 2014-2018 Free Software Foundation, Inc.
Copying and distribution of this script, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. */
OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv",
"elf64-littleriscv")
OUTPUT_ARCH(riscv)
MEMORY
{
/* qemu-system-risc64 virt machine */
RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 128M
}
ENTRY(_start)
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", ORIGIN(RAM))); . = SEGMENT_START("text-segment", ORIGIN(RAM)) + SIZEOF_HEADERS;
PROVIDE(__stack_top = ORIGIN(RAM) + LENGTH(RAM));
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rela.dyn :
{
*(.rela.init)
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
*(.rela.fini)
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
*(.rela.ctors)
*(.rela.dtors)
*(.rela.got)
*(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
*(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
*(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
*(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
.rela.plt :
{
*(.rela.plt)
}
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) }
.iplt : { *(.iplt) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.sdata2 :
{
*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
}
.sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table
.gcc_except_table.*) }
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges : ONLY_IF_RO { *(.exception_ranges
.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
/* Thread Local Storage sections */
.tdata :
{
PROVIDE_HIDDEN (__tdata_start = .);
*(.tdata .tdata.* .gnu.linkonce.td.*)
}
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
}
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
. = DATA_SEGMENT_RELRO_END (0, .);
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
.got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }
/* We want the small data sections together, so single-instruction offsets
can access them all, and initialized data all before uninitialized, so
we can shorten the on-disk segment size. */
.sdata :
{
__global_pointer$ = . + 0x800;
*(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*)
*(.sdata .sdata.* .gnu.linkonce.s.*)
}
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.sbss :
{
*(.dynsbss)
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
}
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
. = ALIGN(64 / 8);
. = SEGMENT_START("ldata-segment", .);
. = ALIGN(64 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}
2) startup.s: (credits: here and here).
.section .init, "ax"
.global _start
_start:
.cfi_startproc
.cfi_undefined ra
.option push
.option norelax
la gp, __global_pointer$
.option pop
la sp, __stack_top
add s0, sp, zero
jal zero, main
.cfi_endproc
.end
add.c: (your code)
int main() {
int a = 4;
int b = 12;
while (1) {
int c = a + b;
}
return 0;
}
3) compiling/linking, and creating a listing:
riscv64-unknown-elf-gcc -g -ffreestanding -O0 -Wl,--gc-sections -nostartfiles -nostdlib -nodefaultlibs -Wl,-T,riscv64-virt.ld -o add.elf startup.s add.c
riscv64-unknown-elf-objdump -D add.elf > add.objdump
4) starting qemu in a console:
qemu-system-riscv64 -machine virt -m 128M -gdb tcp::1234,ipv4 -kernel add.elf
I am not sure that the qemu options you were using: -drive file=a.out,format=raw
are correct, and I think they are not, but I did not spend time checking, and used the options I am usually using: -kernel add.elf
4) starting gdb in another console (I am using here a GDB I compiled with TUI support for mingw64 for my own convenience).
riscv64-elf-gdb --tui add.elf
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
main () at add.c:5
(gdb) p a
$1 = 4
(gdb) p b
$2 = 12
(gdb) p c
$3 = 16
(gdb)
This may have been a little bit long, but I hope this will help.
Please note that the startup code is good enough for your code, but some important initializations are missing, such as copying the data section from flash to RAM (not relevant here), and clearing the .bss section.
Using riscv-gnu-toolchain built with glibc is a much simpler method to debug riscv programs unless you are debugging some system-level program where you must use riscv64-unknown-elf-gcc instead of riscv64-unknown-linux-gnu-gcc. For a simple program like your add.c, using user-space qemu-riscv and glibc riscv-gnu-toolchain can save you a lot of trouble. (One can install these tools following the commands listed at the bottom)
By the time I am writing this answer, there are two different versions of the riscv toolchain: one built with newlib which provides riscv64-unknown-elf-* and another with glibc which provides riscv64-unknown-linux-gnu-*. There are also two versions of qemu: qemu-system-riscv64 for debugging kernels or bare-metal programs and qemu-riscv64 for debugging user-space programs compiled with libc.
For simple programs like add.c, one may debug it with the second type of the toolchain:
Compile: riscv64-unknown-linux-gnu-gcc add.c -o add -g
Run: qemu-riscv64 -L /opt/riscv/sysroot/ -g 1234 add -S
Then launch GDB: riscv64-unknown-linux-gnu-gdb add
Inside GDB:
target remote:1234
b main
c
And the program should break at the main entrance.
(Another option is to statically link the program: riscv64-unknown-linux-gnu-gcc add.c -o add -g -static and then qemu-riscv64 -g 1234 add -S should work as well)
I did not find many documents mentioning user-space riscv qemu. All I found were articles talking about how to use qemu to debug OS kernels with RISC-V ISA. For the convenience of other newcomers to riscv like me, I will show in the following how to build the mentioned tools.
qemu (https://www.qemu.org/download/#source)
wget https://download.qemu.org/qemu-5.0.0.tar.xz
tar xvJf qemu-5.0.0.tar.xz
cd qemu-5.0.0 # higher versions might have problems
./configure --target-list=riscv64-linux-user,riscv64-softmmu
make -j$(nproc)
sudo make install
, where riscv64-softmmu gives you qemu-system-riscv64 and riscv64-linux-user gives you qemu-riscv64.
riscv-gnu-toolchain (https://github.com/riscv/riscv-gnu-toolchain.git)
git clone https://github.com/riscv/riscv-gnu-toolchain.git
sudo apt-get install autoconf automake autotools-dev curl python3 libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev libncurses5-dev
./configure --prefix=/opt/riscv --enable-multilib
sudo make linux # this provides you the glibc set of tools (the ones we need here)
sudo make # this provides you the newlib set of tools

Global variables between C and C++

I'm developing a mixed C/C++ program for an ARM STM32F4, but I have problems in accessing global variables defined in the C part.
Here is a simple test code to reproduce the problem.
test.h:
#ifndef TEST_H_
#define TEST_H_
#ifdef __cplusplus
extern "C" {
#endif
extern const char* strings[];
#ifdef __cplusplus
}
#endif
#endif /* TEST_H_ */
test.c:
#include <test.h>
const char* strings[] = {"string a", "string b", "string c" };
main.hpp
#ifndef MAIN_HPP_
#define MAIN_HPP_
#define STM32F4
#include <test.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#endif /* MAIN_HPP_ */
main.cpp:
#include <main.hpp>
int main(void)
{
char s2[3][9];
rcc_periph_clock_enable(RCC_GPIOD);
gpio_mode_setup(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE,
GPIO12);
while (1) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 9; j++) {
s2[i][j] = strings[i][j];
if (s2[i][j] == 'i') {
gpio_toggle(GPIOD, GPIO12);
}
for (int k = 0; k < 1000000; k++) {
__asm__("nop");
}
}
}
}
}
However, when I run it in the debugger I can see that the memory where strings[0] (for example) is pointing is completely zeroed.
Note: the part in the while loop is not relevant, I've just added it to have some feedback and to avoid that the compiler strips the unused values of strings.
So what am I doing wrong here?
EDIT
I'm working with Eclipse under Linux, gnu-arm-none-eabi.
complier and linker command lines and output:
arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -O0 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -fno-move-loop-invariants -Wunused -Wuninitialized -Wall -Wextra -Wmissing-declarations -Wconversion -Wpointer-arith -Wpadded -Wshadow -Wlogical-op -Waggregate-return -Wfloat-equal -g3 -I"/home/andrea/ownCloud/src/arm/libopencm3/include" -I"/home/andrea/ownCloud/src/arm/testt/src" -std=gnu++11 -fabi-version=0 -fno-exceptions -fno-rtti -fno-use-cxa-atexit -fno-threadsafe-statics -Wabi -Wctor-dtor-privacy -Wnoexcept -Wnon-virtual-dtor -Wstrict-null-sentinel -Wsign-promo -MMD -MP -MF"src/main.d" -MT"src/main.o" -c -o "src/main.o" "../src/main.cpp"
In file included from /home/andrea/ownCloud/src/arm/libopencm3/include/libopencm3/stm32/rcc.h:32:0,
from /home/andrea/ownCloud/src/arm/testt/src/main.hpp:14,
from ../src/main.cpp:20:
/home/andrea/ownCloud/src/arm/libopencm3/include/libopencm3/stm32/f4/rcc.h:640:11: warning: padding struct to align 'rcc_clock_scale::plln' [-Wpadded]
uint16_t plln;
^
/home/andrea/ownCloud/src/arm/libopencm3/include/libopencm3/stm32/f4/rcc.h:644:11: warning: padding struct to align 'rcc_clock_scale::flash_config' [-Wpadded]
uint32_t flash_config;
^
Finished building: ../src/main.cpp
Building file: ../src/test.c
Invoking: Cross ARM C Compiler
arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -O0 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -fno-move-loop-invariants -Wunused -Wuninitialized -Wall -Wextra -Wmissing-declarations -Wconversion -Wpointer-arith -Wpadded -Wshadow -Wlogical-op -Waggregate-return -Wfloat-equal -g3 -I"/home/andrea/ownCloud/src/arm/libopencm3/include" -I"/home/andrea/ownCloud/src/arm/testt/src" -std=gnu11 -Wmissing-prototypes -Wstrict-prototypes -Wbad-function-cast -MMD -MP -MF"src/test.d" -MT"src/test.o" -c -o "src/test.o" "../src/test.c"
Finished building: ../src/test.c
Building target: testt.elf
Invoking: Cross ARM C++ Linker
arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -O0 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -fno-move-loop-invariants -Wunused -Wuninitialized -Wall -Wextra -Wmissing-declarations -Wconversion -Wpointer-arith -Wpadded -Wshadow -Wlogical-op -Waggregate-return -Wfloat-equal -g3 -T "/home/andrea/ownCloud/src/arm/testt/src/stm32f407g-discovery.ld" -T "/home/andrea/ownCloud/src/arm/testt/src/libopencm3_stm32f4.ld" -nostartfiles -Xlinker --gc-sections -L"/home/andrea/ownCloud/src/arm/libopencm3/lib" -Wl,-Map,"testt.map" --specs=nano.specs -o "testt.elf" ./src/main.o ./src/test.o -lopencm3_stm32f4
Finished building target: testt.elf
Linker scripts (not the cleanest one, I did some testing with it).
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
}
_stack_size = 0x400;
/* Include the common ld script. */
INCLUDE libopencm3_stm32f4.ld
libopencm3_stm32f4.ld:
/* Enforce emmition of the vector table. */
EXTERN (vector_table)
/* Define the entry point of the output file. */
ENTRY(reset_handler)
/* Define sections. */
SECTIONS
{
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
} >rom
/* C++ Static constructors/destructors, also used for __attribute__
* ((constructor)) and the likes */
.preinit_array : {
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
} >rom
.init_array : {
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} >rom
.fini_array : {
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
} >rom
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support
*/
.ARM.extab : {
*(.ARM.extab*)
} >rom
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >rom
. = ALIGN(4);
_etext = .;
.data : {
_data = .;
*(.data*) /* Read-write initialized data */
. = ALIGN(4);
_edata = .;
} >ram AT >rom
_data_loadaddr = LOADADDR(.data);
.bss : {
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram
. = ALIGN(4);
_end_bss = .;
end = .;
_end = .;
_heap_bottom = .;
_heap_top = ORIGIN(ram)+LENGTH(ram)-_stack_size;
_stack_bottom =_heap_top;
_stack_top = ORIGIN(ram) + LENGTH(ram);
/*
* The .eh_frame section appears to be used for C++ exception handling.
* You may need to fix this if you're using C++.
*/
/DISCARD/ : { *(.eh_frame) }
}
PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));
EDIT
I'm looking into the problem but I'm a bit puzzled.
The startup code includes the following:
for (src = &_data_loadaddr, dest = &_data;
dest < &_edata;
src++, dest++) {
*dest = *src;
}
So it seems ok to me.
The .map file gives the following infos:
.data 0x0000000020000000 0xc load address 0x000000000800038c
0x0000000020000000 _data = .
*(.data*)
.data.strings 0x0000000020000000 0xc ./src/test.o
0x0000000020000000 strings
0x000000002000000c . = ALIGN (0x4)
0x000000002000000c _edata = .
0x000000002000000c _data = .
*(.data*)
0x000000002000000c . = ALIGN (0x4)
0x000000002000000c _edata = .
0x000000000800038c _data_loadaddr = LOADADDR (.data)
.igot.plt 0x000000002000000c 0x0 load address 0x0000000008000398
Now, when I run the debugger I see that right from the start &_data==&_edata==0x2000000c , and I notice also that _data is present two times in the .map file.
So, is there an error in the linker script?
As Olaf said in a comment, you did not declare your string table as constant. So it is considered by the compiler/linker as initialized read/write data, instead of read only data.
Maybe your initialization code (executed before the main entry point) does not properly copy the initialized data from flash to RAM.
As a quick fix, try to make your string table as constant:
char const * const strings[] = {"string a", "string b", "string c" };
If it works, you could then investigate memory initialization issues... Have a look to the -nostartfiles argument given to the linker, which may probably disable the startup code (to be confirmed)...
The problem finally was with the project configuration in Eclipse: I specified both the .ld files as scripts to be included, but the first already had an include directive for the second file; this caused the double _data specification and the wrong behaviour of the startup code.

gcc undefined reference even though ld finds the library and it contains the desired function

I work on a number of projects for which I must cross compile a number of libraries, some internal, some not. When working on a cross compiled application for one of our systems, I had to import some cross compiled internal libraries for my application. I'm using autotools for the application within Eclipse. The problem happens regardless of whether I'm in Eclipse or not. It happens regardless of platform for which I'm compiling, so all of my various versions of gcc encounter the same linking error. When I compile the application, the individual modules (*.c) compile fine, but when the final gcc command is issued to link everything into the final program, I get an 'undefined reference to GetCanMpdConfig' error.
Now, here's the kicker: the linker actually finds the file (I've verified this with -Wl,--verbose to get gcc to print the linker script). I direct your attention specifically to the line regarding -lcanmpdconf :
Making clean in src
make[1]: Entering directory `/home/amarshall3/workspace/can_mpd/src'
test -z "can_mpd" || rm -f can_mpd
rm -f *.o
make[1]: Leaving directory `/home/amarshall3/workspace/can_mpd/src'
make[1]: Entering directory `/home/amarshall3/workspace/can_mpd'
make[1]: Nothing to be done for `clean-am'.
make[1]: Leaving directory `/home/amarshall3/workspace/can_mpd'
Making all in src
make[1]: Entering directory `/home/amarshall3/workspace/can_mpd/src'
i686-linux-gnu-g++ -DPACKAGE_NAME=\"can_mpd\" -DPACKAGE_TARNAME=\"can_mpd\" -DPACKAGE_VERSION=\"1.13\" -DPACKAGE_STRING=\"can_mpd\ 1.13\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DPLATFORM=generic_x86 -I. -DBUILDSTAMP="\"`date '+%F %T'`\"" -I../dependencies/canmpdconf/1.0/generic_x86/include -I../dependencies/mow2monitor/1.0/generic_x86/include -DGENERIC_X86 -g -ggdb -O0 -Wall -Wl,--verbose -MT can_mpd-can_mpd.o -MD -MP -MF .deps/can_mpd-can_mpd.Tpo -c -o can_mpd-can_mpd.o `test -f 'can_mpd.cpp' || echo './'`can_mpd.cpp
mv -f .deps/can_mpd-can_mpd.Tpo .deps/can_mpd-can_mpd.Po
i686-linux-gnu-g++ -DPACKAGE_NAME=\"can_mpd\" -DPACKAGE_TARNAME=\"can_mpd\" -DPACKAGE_VERSION=\"1.13\" -DPACKAGE_STRING=\"can_mpd\ 1.13\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DPLATFORM=generic_x86 -I. -DBUILDSTAMP="\"`date '+%F %T'`\"" -I../dependencies/canmpdconf/1.0/generic_x86/include -I../dependencies/mow2monitor/1.0/generic_x86/include -DGENERIC_X86 -g -ggdb -O0 -Wall -Wl,--verbose -MT can_mpd-mpd_can.o -MD -MP -MF .deps/can_mpd-mpd_can.Tpo -c -o can_mpd-mpd_can.o `test -f 'mpd_can.cpp' || echo './'`mpd_can.cpp
mv -f .deps/can_mpd-mpd_can.Tpo .deps/can_mpd-mpd_can.Po
i686-linux-gnu-g++ -DPACKAGE_NAME=\"can_mpd\" -DPACKAGE_TARNAME=\"can_mpd\" -DPACKAGE_VERSION=\"1.13\" -DPACKAGE_STRING=\"can_mpd\ 1.13\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DPLATFORM=generic_x86 -I. -DBUILDSTAMP="\"`date '+%F %T'`\"" -I../dependencies/canmpdconf/1.0/generic_x86/include -I../dependencies/mow2monitor/1.0/generic_x86/include -DGENERIC_X86 -g -ggdb -O0 -Wall -Wl,--verbose -MT can_mpd-mpd_multiplexing.o -MD -MP -MF .deps/can_mpd-mpd_multiplexing.Tpo -c -o can_mpd-mpd_multiplexing.o `test -f 'mpd_multiplexing.cpp' || echo './'`mpd_multiplexing.cpp
mv -f .deps/can_mpd-mpd_multiplexing.Tpo .deps/can_mpd-mpd_multiplexing.Po
i686-linux-gnu-g++ -DPACKAGE_NAME=\"can_mpd\" -DPACKAGE_TARNAME=\"can_mpd\" -DPACKAGE_VERSION=\"1.13\" -DPACKAGE_STRING=\"can_mpd\ 1.13\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DPLATFORM=generic_x86 -I. -DBUILDSTAMP="\"`date '+%F %T'`\"" -I../dependencies/canmpdconf/1.0/generic_x86/include -I../dependencies/mow2monitor/1.0/generic_x86/include -DGENERIC_X86 -g -ggdb -O0 -Wall -Wl,--verbose -MT can_mpd-serial_can_provider.o -MD -MP -MF .deps/can_mpd-serial_can_provider.Tpo -c -o can_mpd-serial_can_provider.o `test -f 'provider/serial_can_provider.cpp' || echo './'`provider/serial_can_provider.cpp
mv -f .deps/can_mpd-serial_can_provider.Tpo .deps/can_mpd-serial_can_provider.Po
i686-linux-gnu-g++ -DPACKAGE_NAME=\"can_mpd\" -DPACKAGE_TARNAME=\"can_mpd\" -DPACKAGE_VERSION=\"1.13\" -DPACKAGE_STRING=\"can_mpd\ 1.13\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DPLATFORM=generic_x86 -I. -DBUILDSTAMP="\"`date '+%F %T'`\"" -I../dependencies/canmpdconf/1.0/generic_x86/include -I../dependencies/mow2monitor/1.0/generic_x86/include -DGENERIC_X86 -g -ggdb -O0 -Wall -Wl,--verbose -MT can_mpd-komodo_can_provider.o -MD -MP -MF .deps/can_mpd-komodo_can_provider.Tpo -c -o can_mpd-komodo_can_provider.o `test -f 'provider/komodo_can_provider.cpp' || echo './'`provider/komodo_can_provider.cpp
mv -f .deps/can_mpd-komodo_can_provider.Tpo .deps/can_mpd-komodo_can_provider.Po
i686-linux-gnu-gcc -DPACKAGE_NAME=\"can_mpd\" -DPACKAGE_TARNAME=\"can_mpd\" -DPACKAGE_VERSION=\"1.13\" -DPACKAGE_STRING=\"can_mpd\ 1.13\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DPLATFORM=generic_x86 -I. -g -O2 -MT komodo.o -MD -MP -MF .deps/komodo.Tpo -c -o komodo.o `test -f 'can/komodo/komodo.c' || echo './'`can/komodo/komodo.c
mv -f .deps/komodo.Tpo .deps/komodo.Po
i686-linux-gnu-g++ -DBUILDSTAMP="\"`date '+%F %T'`\"" -I../dependencies/canmpdconf/1.0/generic_x86/include -I../dependencies/mow2monitor/1.0/generic_x86/include -DGENERIC_X86 -g -ggdb -O0 -Wall -Wl,--verbose -L../dependencies/canmpdconf/1.0/generic_x86/lib -L../dependencies/mow2monitor/1.0/generic_x86/lib -Wl,--verbose -o can_mpd can_mpd-can_mpd.o can_mpd-mpd_can.o can_mpd-mpd_multiplexing.o can_mpd-serial_can_provider.o can_mpd-komodo_can_provider.o komodo.o -lcanmpdconf -lmow2monitor -lpthread -ldl
GNU ld (GNU Binutils for Ubuntu) 2.23.52.20130913
Supported emulations:
elf_i386
i386linux
elf32_x86_64
elf_x86_64
elf_l1om
elf_k1om
i386pep
i386pe
GNU ld (GNU Binutils for Ubuntu) 2.23.52.20130913
Supported emulations:
elf_i386
i386linux
elf32_x86_64
elf_x86_64
elf_l1om
elf_k1om
i386pep
i386pe
using internal linker script:
==================================================
/* Script for -z combreloc: combine and sort reloc sections */
OUTPUT_FORMAT("elf32-i386", "elf32-i386",
"elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SEARCH_DIR("/usr/i686-linux-gnu/lib32"); SEARCH_DIR("=/usr/local/lib32"); SEARCH_DIR("=/lib32"); SEARCH_DIR("=/usr/lib32"); SEARCH_DIR("=/usr/local/lib/i386-linux-gnu"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib/i386-linux-gnu"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib/i386-linux-gnu"); SEARCH_DIR("=/usr/lib");
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x08048000)); . = SEGMENT_START("text-segment", 0x08048000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rel.dyn :
{
*(.rel.init)
*(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
*(.rel.fini)
*(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
*(.rel.data.rel.ro .rel.data.rel.ro.* .rel.gnu.linkonce.d.rel.ro.*)
*(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
*(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
*(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
*(.rel.ctors)
*(.rel.dtors)
*(.rel.got)
*(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
*(.rel.ifunc)
}
.rel.plt :
{
*(.rel.plt)
PROVIDE_HIDDEN (__rel_iplt_start = .);
*(.rel.iplt)
PROVIDE_HIDDEN (__rel_iplt_end = .);
}
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) *(.iplt) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.eh_frame_hdr : { *(.eh_frame_hdr) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table
.gcc_except_table.*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges : ONLY_IF_RO { *(.exception_ranges
.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
/* Thread Local Storage sections */
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
}
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
.got : { *(.got) *(.igot) }
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 12 ? 12 : 0, .);
.got.plt : { *(.got.plt) *(.igot.plt) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 32 / 8 : 1);
}
. = ALIGN(32 / 8);
. = SEGMENT_START("ldata-segment", .);
. = ALIGN(32 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}
==================================================
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/../../../i386-linux-gnu/crt1.o succeeded
/usr/lib/gcc/i686-linux-gnu/4.8/../../../i386-linux-gnu/crt1.o
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/../../../i386-linux-gnu/crti.o succeeded
/usr/lib/gcc/i686-linux-gnu/4.8/../../../i386-linux-gnu/crti.o
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/crtbegin.o succeeded
/usr/lib/gcc/i686-linux-gnu/4.8/crtbegin.o
attempt to open can_mpd-can_mpd.o succeeded
can_mpd-can_mpd.o
attempt to open can_mpd-mpd_can.o succeeded
can_mpd-mpd_can.o
attempt to open can_mpd-mpd_multiplexing.o succeeded
can_mpd-mpd_multiplexing.o
attempt to open can_mpd-serial_can_provider.o succeeded
can_mpd-serial_can_provider.o
attempt to open can_mpd-komodo_can_provider.o succeeded
can_mpd-komodo_can_provider.o
attempt to open komodo.o succeeded
komodo.o
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libcanmpdconf.so succeeded
-lcanmpdconf (../dependencies/canmpdconf/1.0/generic_x86/lib/libcanmpdconf.so)
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libmow2monitor.so failed
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libmow2monitor.a failed
attempt to open ../dependencies/mow2monitor/1.0/generic_x86/lib/libmow2monitor.so succeeded
-lmow2monitor (../dependencies/mow2monitor/1.0/generic_x86/lib/libmow2monitor.so)
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libpthread.so failed
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libpthread.a failed
attempt to open ../dependencies/mow2monitor/1.0/generic_x86/lib/libpthread.so failed
attempt to open ../dependencies/mow2monitor/1.0/generic_x86/lib/libpthread.a failed
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/libpthread.so failed
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/libpthread.a failed
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/../../../i386-linux-gnu/libpthread.so succeeded
opened script file /usr/lib/gcc/i686-linux-gnu/4.8/../../../i386-linux-gnu/libpthread.so
opened script file /usr/lib/gcc/i686-linux-gnu/4.8/../../../i386-linux-gnu/libpthread.so
attempt to open /lib/i386-linux-gnu/libpthread.so.0 succeeded
/lib/i386-linux-gnu/libpthread.so.0
attempt to open /usr/lib/i386-linux-gnu/libpthread_nonshared.a succeeded
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libdl.so failed
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libdl.a failed
attempt to open ../dependencies/mow2monitor/1.0/generic_x86/lib/libdl.so failed
attempt to open ../dependencies/mow2monitor/1.0/generic_x86/lib/libdl.a failed
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/libdl.so failed
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/libdl.a failed
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/../../../i386-linux-gnu/libdl.so succeeded
-ldl (/usr/lib/gcc/i686-linux-gnu/4.8/../../../i386-linux-gnu/libdl.so)
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libstdc++.so failed
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libstdc++.a failed
attempt to open ../dependencies/mow2monitor/1.0/generic_x86/lib/libstdc++.so failed
attempt to open ../dependencies/mow2monitor/1.0/generic_x86/lib/libstdc++.a failed
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/libstdc++.so succeeded
-lstdc++ (/usr/lib/gcc/i686-linux-gnu/4.8/libstdc++.so)
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libm.so failed
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libm.a failed
attempt to open ../dependencies/mow2monitor/1.0/generic_x86/lib/libm.so failed
attempt to open ../dependencies/mow2monitor/1.0/generic_x86/lib/libm.a failed
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/libm.so failed
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/libm.a failed
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/../../../i386-linux-gnu/libm.so succeeded
-lm (/usr/lib/gcc/i686-linux-gnu/4.8/../../../i386-linux-gnu/libm.so)
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libgcc_s.so failed
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libgcc_s.a failed
attempt to open ../dependencies/mow2monitor/1.0/generic_x86/lib/libgcc_s.so failed
attempt to open ../dependencies/mow2monitor/1.0/generic_x86/lib/libgcc_s.a failed
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/libgcc_s.so succeeded
-lgcc_s (/usr/lib/gcc/i686-linux-gnu/4.8/libgcc_s.so)
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libgcc.so failed
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libgcc.a failed
attempt to open ../dependencies/mow2monitor/1.0/generic_x86/lib/libgcc.so failed
attempt to open ../dependencies/mow2monitor/1.0/generic_x86/lib/libgcc.a failed
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/libgcc.so failed
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/libgcc.a succeeded
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libc.so failed
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libc.a failed
attempt to open ../dependencies/mow2monitor/1.0/generic_x86/lib/libc.so failed
attempt to open ../dependencies/mow2monitor/1.0/generic_x86/lib/libc.a failed
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/libc.so failed
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/libc.a failed
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/../../../i386-linux-gnu/libc.so succeeded
opened script file /usr/lib/gcc/i686-linux-gnu/4.8/../../../i386-linux-gnu/libc.so
opened script file /usr/lib/gcc/i686-linux-gnu/4.8/../../../i386-linux-gnu/libc.so
attempt to open /lib/i386-linux-gnu/libc.so.6 succeeded
/lib/i386-linux-gnu/libc.so.6
attempt to open /usr/lib/i386-linux-gnu/libc_nonshared.a succeeded
(/usr/lib/i386-linux-gnu/libc_nonshared.a)elf-init.oS
(/usr/lib/i386-linux-gnu/libc_nonshared.a)atexit.oS
attempt to open /lib/i386-linux-gnu/ld-linux.so.2 succeeded
/lib/i386-linux-gnu/ld-linux.so.2
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libgcc_s.so failed
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libgcc_s.a failed
attempt to open ../dependencies/mow2monitor/1.0/generic_x86/lib/libgcc_s.so failed
attempt to open ../dependencies/mow2monitor/1.0/generic_x86/lib/libgcc_s.a failed
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/libgcc_s.so succeeded
-lgcc_s (/usr/lib/gcc/i686-linux-gnu/4.8/libgcc_s.so)
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libgcc.so failed
attempt to open ../dependencies/canmpdconf/1.0/generic_x86/lib/libgcc.a failed
attempt to open ../dependencies/mow2monitor/1.0/generic_x86/lib/libgcc.so failed
attempt to open ../dependencies/mow2monitor/1.0/generic_x86/lib/libgcc.a failed
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/libgcc.so failed
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/libgcc.a succeeded
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/crtend.o succeeded
/usr/lib/gcc/i686-linux-gnu/4.8/crtend.o
attempt to open /usr/lib/gcc/i686-linux-gnu/4.8/../../../i386-linux-gnu/crtn.o succeeded
/usr/lib/gcc/i686-linux-gnu/4.8/../../../i386-linux-gnu/crtn.o
ld-linux.so.2 needed by /lib/i386-linux-gnu/libpthread.so.0
found ld-linux.so.2 at /lib/i386-linux-gnu/ld-linux.so.2
libm.so.6 needed by /usr/lib/gcc/i686-linux-gnu/4.8/libstdc++.so
found libm.so at /usr/lib/gcc/i686-linux-gnu/4.8/../../../i386-linux-gnu/libm.so
make[1]: Leaving directory `/home/amarshall3/workspace/can_mpd/src'
can_mpd-can_mpd.o: In function `main':
/home/amarshall3/workspace/can_mpd/src/can_mpd.cpp:180: undefined reference to `GetCanMpdConfig(CAN_MPD_CONFIG*, unsigned int*)'
collect2: error: ld returned 1 exit status
make[1]: *** [can_mpd] Error 1
make: *** [all-recursive] Error 1
I have also verified that the library is for the correct platform (x86) and so therefore is in the correct format. I've also verified that it does indeed contain the required symbol (GetCanMpdConfig) with the output of nm:
0000305c B __bss_start
0000305c b completed.6608
w __cxa_finalize##GLIBC_2.1.3
00000940 t deregister_tm_clones
000009d0 t __do_global_dtors_aux
00002e88 t __do_global_dtors_aux_fini_array_entry
00003058 d __dso_handle
00002ee4 d _DYNAMIC
0000305c D _edata
00003060 B _end
U __errno_location##GLIBC_2.0
00002ea0 d Errors
U fclose##GLIBC_2.1
U fgets##GLIBC_2.0
00001184 T _fini
U fopen##GLIBC_2.1
U __fprintf_chk##GLIBC_2.3.4
00000a20 t frame_dummy
00002e84 t __frame_dummy_init_array_entry
000014e8 r __FRAME_END__
00000ef0 T GetCanMpdConfError
00000b60 T GetCanMpdConfig
00000a60 T GetCanMpdConfVersion
U GetConfigFilePath
00003000 d _GLOBAL_OFFSET_TABLE_
w __gmon_start__
00002ec0 d Handlers
000007c4 T _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
00002e8c d __JCR_END__
00002e8c d __JCR_LIST__
w _Jv_RegisterClasses
00000f20 T read_provider_type
000010c0 T read_serial_baud
00001010 T read_serial_device
00000980 t register_tm_clones
00000a80 T SetCanMpdConfig
U __stack_chk_fail##GLIBC_2.4
00001170 t __stack_chk_fail_local
U strchr##GLIBC_2.0
U strlen##GLIBC_2.0
U strncmp##GLIBC_2.0
U strncpy##GLIBC_2.0
U strtol##GLIBC_2.0
0000305c d __TMC_END__
00000f90 T write_provider_type
00001110 T write_serial_baud
00001060 T write_serial_device
00000930 t __x86.get_pc_thunk.bx
00000f18 t __x86.get_pc_thunk.cx
U __xstat##GLIBC_2.0
To summarize:
1) Linking order in the gcc commands is correct (-llibname after -o blah.cpp)
2) Linker finds the library (libcanmpdconf.so)
3) Library is in the correct format for the platform (x86)
4) Library contains the symbol (see nm output)
There should be no reason, as far as I can tell, why there should be an undefined reference to any symbol that clearly exists in my library, which the linker can find. Does anybody know of any other ways I can try to troubleshoot this or what might be wrong ?
Could you be facing an
extern "C"
problem?

Cross g++ compiler linker error

I am using Eclipse to cross compile a g++ project for an ARM processor. I am using the yagarto toolchain in a Windows environment. I have no issues with C projects, but with C++ I keep receiving the errors:
libc.a(lib_a-abort.o): In function `abort':
abort.c:63: undefined reference to `_exit'
libc.a(lib_a-sbrkr.o): In function `_sbrk_r':
sbrkr.c:58 undefined reference to `_sbrk'
libc.a(lib_a-signalr.o): In function `_kill_r':
signalr.c:61: undefined reference to `_kill'
as well as:
undefined reference to `_getpid'
undefined reference to `_write'
undefined reference to `_close'
undefined reference to `_fstat'
undefined reference to `_isatty'
undefined reference to `_lseek'
undefined reference to `_read'
From looking around it looks like I have a linker issue. I tried to add the linker flash.ld. It is from a GCC example for my ARM development kit from Atmel Studio. It is not helping. Is there a linker for g++ somewhere? Do I have another issue?
Here are my build options:
make all
Building target: Foo
Invoking: Cross G++ Linker
arm-none-eabi-g++ -nostartfiles -T C:/Users/kempsa/eclipse_workspace/Foo/flash.ld -o"Foo" ./HALTimer1.o ./Main.o
I have the source files Main.cpp, HALTimer1.cpp and the header file Haltimer.h. The main file only includes the header file. The header file only defines a class for the HALTimer with one variable. I don't believe these affect the error. I believe the error is solely from tying to build a g++ project without the correct linker file.
Here is the content of the linker file:
/**
* \file
*
* \brief Flash Linker script for SAM.
*
* Copyright (c) 2011-2012 Atmel Corporation. All rights reserved.
*
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SEARCH_DIR(.)
/* Memory Spaces Definitions */
MEMORY
{
rom (rx) : ORIGIN = 0x00400000, LENGTH = 0x00040000 /* flash has two banks, one bank = 256K */
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00010000 /* sram, 64K */
}
/* The stack size used by the application. NOTE: you need to adjust */
__stack_size__ = DEFINED(__stack_size__) ? __stack_size__ : 0x2000;
/* Section Definitions */
SECTIONS
{
.text :
{
. = ALIGN(4);
_sfixed = .;
KEEP(*(.vectors .vectors.*))
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
*(.rodata .rodata* .gnu.linkonce.r.*)
*(.ARM.extab* .gnu.linkonce.armextab.*)
/* Support C constructors, and C destructors in both user code
and the C library. This also provides support for C++ code. */
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
. = ALIGN(0x4);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
. = ALIGN(4);
KEEP(*(.fini))
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
. = ALIGN(4);
_efixed = .; /* End of text section */
} > rom
/* .ARM.exidx is sorted, so has to go in its own output section. */
PROVIDE_HIDDEN (__exidx_start = .);
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > rom
PROVIDE_HIDDEN (__exidx_end = .);
. = ALIGN(4);
_etext = .;
.relocate : AT (_etext)
{
. = ALIGN(4);
_srelocate = .;
*(.ramfunc .ramfunc.*);
*(.data .data.*);
. = ALIGN(4);
_erelocate = .;
} > ram
/* .bss section which is used for uninitialized data */
.bss (NOLOAD) :
{
. = ALIGN(4);
_sbss = . ;
_szero = .;
*(.bss .bss.*)
*(COMMON)
. = ALIGN(4);
_ebss = . ;
_ezero = .;
} > ram
/* stack section */
.stack (NOLOAD):
{
. = ALIGN(8);
_sstack = .;
. = . + __stack_size__;
. = ALIGN(8);
_estack = .;
} > ram
. = ALIGN(4);
_end = . ;
}
Complete compiler output:
Building target: Foo
Invoking: Cross G++ Linker
arm-none-eabi-g++ -nostartfiles -T C:/Users/kempsa/eclipse_workspace/Foo/flash.ld -o"Foo" ./HALTimer.o ./Main.o
c:/yagarto/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib\libc.a(lib_a-abort.o): In function `abort':
C:\msys\1.0\home\yagarto\newlib-build\arm-none-eabi\newlib\libc\stdlib/../../../../../newlib-1.20.0/newlib/libc/stdlib/abort.c:63: undefined reference to `_exit'
c:/yagarto/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib\libc.a(lib_a-sbrkr.o): In function `_sbrk_r':
C:\msys\1.0\home\yagarto\newlib-build\arm-none-eabi\newlib\libc\reent/../../../../../newlib-1.20.0/newlib/libc/reent/sbrkr.c:58: undefined reference to `_sbrk'
c:/yagarto/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib\libc.a(lib_a-signalr.o): In function `_kill_r':
C:\msys\1.0\home\yagarto\newlib-build\arm-none-eabi\newlib\libc\reent/../../../../../newlib-1.20.0/newlib/libc/reent/signalr.c:61: undefined reference to `_kill'
c:/yagarto/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib\libc.a(lib_a-signalr.o): In function `_getpid_r':
C:\msys\1.0\home\yagarto\newlib-build\arm-none-eabi\newlib\libc\reent/../../../../../newlib-1.20.0/newlib/libc/reent/signalr.c:96: undefined reference to `_getpid'
c:/yagarto/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib\libc.a(lib_a-writer.o): In function `_write_r':
C:\msys\1.0\home\yagarto\newlib-build\arm-none-eabi\newlib\libc\reent/../../../../../newlib-1.20.0/newlib/libc/reent/writer.c:58: undefined reference to `_write'
c:/yagarto/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib\libc.a(lib_a-closer.o): In function `_close_r':
C:\msys\1.0\home\yagarto\newlib-build\arm-none-eabi\newlib\libc\reent/../../../../../newlib-1.20.0/newlib/libc/reent/closer.c:53: undefined reference to `_close'
c:/yagarto/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib\libc.a(lib_a-fstatr.o): In function `_fstat_r':
C:\msys\1.0\home\yagarto\newlib-build\arm-none-eabi\newlib\libc\reent/../../../../../newlib-1.20.0/newlib/libc/reent/fstatr.c:62: undefined reference to `_fstat'
c:/yagarto/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib\libc.a(lib_a-isattyr.o): In function `_isatty_r':
C:\msys\1.0\home\yagarto\newlib-build\arm-none-eabi\newlib\libc\reent/../../../../../newlib-1.20.0/newlib/libc/reent/isattyr.c:58: undefined reference to `_isatty'
c:/yagarto/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib\libc.a(lib_a-lseekr.o): In function `_lseek_r':
C:\msys\1.0\home\yagarto\newlib-build\arm-none-eabi\newlib\libc\reent/../../../../../newlib-1.20.0/newlib/libc/reent/lseekr.c:58: undefined reference to `_lseek'
c:/yagarto/bin/../lib/gcc/arm-none-eabi/4.7.2/../../../../arm-none-eabi/lib\libc.a(lib_a-readr.o): In function `_read_r':
C:\msys\1.0\home\yagarto\newlib-build\arm-none-eabi\newlib\libc\reent/../../../../../newlib-1.20.0/newlib/libc/reent/readr.c:58: undefined reference to `_read'
collect2.exe: error: ld returned 1 exit status
make: *** [Foo] Error 1
Add the linker options -Wl,--gc-sections and the problem should be resolved