What linkerscript does Arduino IDE use when compiling for the Arduino UNO? - c++

1. What I'm trying to achieve
My ultimate goal is to convert Arduino projects (sketches) into makefile-based self-contained C/C++ projects.
I already made some progress (thanks #Juraj for your helpful comments). I copy all the relevant Arduino *.cpp and *.h files to a folder (which I call my "project folder") as well as the preprocessed sketch file (the Arduino preprocessor turns the sketch file into a *.cpp file).
I added an in-house makefile and the build works very well. However, in the last step - the linking - it's still a mystery to me what linkerscript is being used exactly.
2. The problem explained
Although the build - including the linking step - works very well, I'd like to know what linkerscript is being used. Right now, the avr-gcc toolchain chooses a linkerscript from its installation folder:
<arduino ide installation>/hardware/tools/avr/avr/lib/ldscripts
As #Juraj explains in the comments, the toolchain bases its choice on the -mmcu flag.
I don't want the compiler to choose a fixed linkerscript from the avr-gcc toolchain. Instead, I want to copy this linkerscript right into my project folder and be able to tweak it. But to do that - I must first know which linkerscript it is. How can I know?
3. Background info
Below you can find more information about my setup and system.
3.1. My setup
I've got an Arduino UNO R3 which is based on the ATmega328P microcontroller. I'm working in Ubuntu 20.04.1 LTS.
I installed the Arduino IDE and created a new project from:
File > Examples > 01.Basics > Blink
I saved the new project at ~/Arduino/sketch_uno_blinky/sketch_uno_blinky.ino
Finally I ticked the checkmark at:
File > Preferences > Show verbose output
such that I can see the compilation output properly. Based on that, I could track all the *.cpp and *.h files that take part in the build. I copied them to a folder to make my own self-contained makefile-based project.
3.2 Linking
I run the linker like this:
avr-gcc -Wl,-Map=output.map
-Wl,--gc-sections
-mmcu=atmega328p
-DF_CPU=16000000L
-DARDUINO=10813
-DARDUINO_AVR_UNO
-DARDUINO_ARCH_AVR
-Og
-g3
-MMD
-fmessage-length=0
-ffunction-sections
-fdata-sections
-Wno-comment
-Wno-unused-function
-Werror-implicit-function-declaration
-w
-lm
-flto
-fuse-linker-plugin
-L ../config/
-o application.elf
WInterrupts.o
main.o
hooks.o
wiring.o
wiring_analog.o
wiring_digital.o
wiring_pulse.o
wiring_shift.o
[...]
sketch_uno_blinky.ino.o
which results in the application.elf firmware.

The -mcu option of avr-ld determines the linker script. It selects from linker scripts bundled with avr-gcc. With Arduino this folder is bundled with Arduino IDE in installation folder in hardware/tools/avr/avr/lib/ldscript or with one of the avr-gcc versions in arduion15 folder in packages/arduino/tools/avr-gcc.
In avr-gcc surce code there is a avr-mcus.def file which describes the AVR MCUs. The second column in the file is the 'architecture' and you can find a corresponding linker script in ldscripts. For example atmega328p has ARCH_AVR5 and the linker script is avr5.x

Thank you #Juraj for your answer and all the helpful comments!
I've found another way to see what linkerscript is being used. Just add this flag to the linker invocation:
-Wl,--verbose
I get the following output:
GNU ld (GNU Binutils) 2.26.20160125
Supported emulations:
avr2
avr1
avr25
avr3
avr31
avr35
avr4
avr5
avr51
avr6
avrxmega1
avrxmega2
avrxmega3
avrxmega4
avrxmega5
avrxmega6
avrxmega7
avrtiny
opened script file /home/kristof/gnu_avr_toolchain/avr/bin/../lib/ldscripts/avr5.xn
using external linker script:
==================================================
/* Script for -n: mix text and data on same page */
/* Copyright (C) 2014-2015 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("elf32-avr","elf32-avr","elf32-avr")
OUTPUT_ARCH(avr:5)
__TEXT_REGION_LENGTH__ = DEFINED(__TEXT_REGION_LENGTH__) ? __TEXT_REGION_LENGTH__ : 128K;
__DATA_REGION_LENGTH__ = DEFINED(__DATA_REGION_LENGTH__) ? __DATA_REGION_LENGTH__ : 0xffa0;
__EEPROM_REGION_LENGTH__ = DEFINED(__EEPROM_REGION_LENGTH__) ? __EEPROM_REGION_LENGTH__ : 64K;
__FUSE_REGION_LENGTH__ = DEFINED(__FUSE_REGION_LENGTH__) ? __FUSE_REGION_LENGTH__ : 1K;
__LOCK_REGION_LENGTH__ = DEFINED(__LOCK_REGION_LENGTH__) ? __LOCK_REGION_LENGTH__ : 1K;
__SIGNATURE_REGION_LENGTH__ = DEFINED(__SIGNATURE_REGION_LENGTH__) ? __SIGNATURE_REGION_LENGTH__ : 1K;
__USER_SIGNATURE_REGION_LENGTH__ = DEFINED(__USER_SIGNATURE_REGION_LENGTH__) ? __USER_SIGNATURE_REGION_LENGTH__ : 1K;
__DATA_REGION_ORIGIN__ = DEFINED(__DATA_REGION_ORIGIN__) ? __DATA_REGION_ORIGIN__ : 0x800060;
MEMORY
{
text (rx) : ORIGIN = 0, LENGTH = __TEXT_REGION_LENGTH__
data (rw!x) : ORIGIN = __DATA_REGION_ORIGIN__, LENGTH = __DATA_REGION_LENGTH__
eeprom (rw!x) : ORIGIN = 0x810000, LENGTH = __EEPROM_REGION_LENGTH__
fuse (rw!x) : ORIGIN = 0x820000, LENGTH = __FUSE_REGION_LENGTH__
lock (rw!x) : ORIGIN = 0x830000, LENGTH = __LOCK_REGION_LENGTH__
signature (rw!x) : ORIGIN = 0x840000, LENGTH = __SIGNATURE_REGION_LENGTH__
user_signatures (rw!x) : ORIGIN = 0x850000, LENGTH = __USER_SIGNATURE_REGION_LENGTH__
}
SECTIONS
{
/* Read-only sections, merged into text segment: */
.hash : { *(.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rel.init : { *(.rel.init) }
.rela.init : { *(.rela.init) }
.rel.text :
{
*(.rel.text)
*(.rel.text.*)
*(.rel.gnu.linkonce.t*)
}
.rela.text :
{
*(.rela.text)
*(.rela.text.*)
*(.rela.gnu.linkonce.t*)
}
.rel.fini : { *(.rel.fini) }
.rela.fini : { *(.rela.fini) }
.rel.rodata :
{
*(.rel.rodata)
*(.rel.rodata.*)
*(.rel.gnu.linkonce.r*)
}
.rela.rodata :
{
*(.rela.rodata)
*(.rela.rodata.*)
*(.rela.gnu.linkonce.r*)
}
.rel.data :
{
*(.rel.data)
*(.rel.data.*)
*(.rel.gnu.linkonce.d*)
}
.rela.data :
{
*(.rela.data)
*(.rela.data.*)
*(.rela.gnu.linkonce.d*)
}
.rel.ctors : { *(.rel.ctors) }
.rela.ctors : { *(.rela.ctors) }
.rel.dtors : { *(.rel.dtors) }
.rela.dtors : { *(.rela.dtors) }
.rel.got : { *(.rel.got) }
.rela.got : { *(.rela.got) }
.rel.bss : { *(.rel.bss) }
.rela.bss : { *(.rela.bss) }
.rel.plt : { *(.rel.plt) }
.rela.plt : { *(.rela.plt) }
/* Internal text space or external memory. */
.text :
{
*(.vectors)
KEEP(*(.vectors))
/* For data that needs to reside in the lower 64k of progmem. */
*(.progmem.gcc*)
/* PR 13812: Placing the trampolines here gives a better chance
that they will be in range of the code that uses them. */
. = ALIGN(2);
__trampolines_start = . ;
/* The jump trampolines for the 16-bit limited relocs will reside here. */
*(.trampolines)
*(.trampolines*)
__trampolines_end = . ;
/* avr-libc expects these data to reside in lower 64K. */
*libprintf_flt.a:*(.progmem.data)
*libc.a:*(.progmem.data)
*(.progmem*)
. = ALIGN(2);
/* For future tablejump instruction arrays for 3 byte pc devices.
We don't relax jump/call instructions within these sections. */
*(.jumptables)
*(.jumptables*)
/* For code that needs to reside in the lower 128k progmem. */
*(.lowtext)
*(.lowtext*)
__ctors_start = . ;
*(.ctors)
__ctors_end = . ;
__dtors_start = . ;
*(.dtors)
__dtors_end = . ;
KEEP(SORT(*)(.ctors))
KEEP(SORT(*)(.dtors))
/* From this point on, we don't bother about wether the insns are
below or above the 16 bits boundary. */
*(.init0) /* Start here after reset. */
KEEP (*(.init0))
*(.init1)
KEEP (*(.init1))
*(.init2) /* Clear __zero_reg__, set up stack pointer. */
KEEP (*(.init2))
*(.init3)
KEEP (*(.init3))
*(.init4) /* Initialize data and BSS. */
KEEP (*(.init4))
*(.init5)
KEEP (*(.init5))
*(.init6) /* C++ constructors. */
KEEP (*(.init6))
*(.init7)
KEEP (*(.init7))
*(.init8)
KEEP (*(.init8))
*(.init9) /* Call main(). */
KEEP (*(.init9))
*(.text)
. = ALIGN(2);
*(.text.*)
. = ALIGN(2);
*(.fini9) /* _exit() starts here. */
KEEP (*(.fini9))
*(.fini8)
KEEP (*(.fini8))
*(.fini7)
KEEP (*(.fini7))
*(.fini6) /* C++ destructors. */
KEEP (*(.fini6))
*(.fini5)
KEEP (*(.fini5))
*(.fini4)
KEEP (*(.fini4))
*(.fini3)
KEEP (*(.fini3))
*(.fini2)
KEEP (*(.fini2))
*(.fini1)
KEEP (*(.fini1))
*(.fini0) /* Infinite loop after program termination. */
KEEP (*(.fini0))
_etext = . ;
} > text
.data :
{
PROVIDE (__data_start = .) ;
*(.data)
*(.data*)
*(.gnu.linkonce.d*)
*(.rodata) /* We need to include .rodata here if gcc is used */
*(.rodata*) /* with -fdata-sections. */
*(.gnu.linkonce.r*)
. = ALIGN(2);
_edata = . ;
PROVIDE (__data_end = .) ;
} > data AT> text
.bss ADDR(.data) + SIZEOF (.data) : AT (ADDR (.bss))
{
PROVIDE (__bss_start = .) ;
*(.bss)
*(.bss*)
*(COMMON)
PROVIDE (__bss_end = .) ;
} > data
__data_load_start = LOADADDR(.data);
__data_load_end = __data_load_start + SIZEOF(.data);
/* Global data not cleared after reset. */
.noinit ADDR(.bss) + SIZEOF (.bss) : AT (ADDR (.noinit))
{
PROVIDE (__noinit_start = .) ;
*(.noinit*)
PROVIDE (__noinit_end = .) ;
_end = . ;
PROVIDE (__heap_start = .) ;
} > data
.eeprom :
{
/* See .data above... */
KEEP(*(.eeprom*))
__eeprom_end = . ;
} > eeprom
.fuse :
{
KEEP(*(.fuse))
KEEP(*(.lfuse))
KEEP(*(.hfuse))
KEEP(*(.efuse))
} > fuse
.lock :
{
KEEP(*(.lock*))
} > lock
.signature :
{
KEEP(*(.signature*))
} > signature
.user_signatures :
{
KEEP(*(.user_signatures*))
} > user_signatures
/* 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) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
/* 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) }
}
==================================================
attempt to open /home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o succeeded
/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/crtatmega328p.o
attempt to open ../config//libm.so failed
attempt to open ../config//libm.a failed
attempt to open /home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libm.so failed
attempt to open /home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libm.a failed
attempt to open /home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libm.so failed
attempt to open /home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libm.a succeeded
attempt to open WInterrupts.o succeeded
WInterrupts.o
attempt to open hooks.o succeeded
hooks.o
attempt to open wiring.o succeeded
wiring.o
attempt to open wiring_analog.o succeeded
wiring_analog.o
attempt to open wiring_digital.o succeeded
wiring_digital.o
attempt to open wiring_pulse.o succeeded
wiring_pulse.o
attempt to open wiring_shift.o succeeded
wiring_shift.o
attempt to open CDC.o succeeded
CDC.o
attempt to open HardwareSerial.o succeeded
HardwareSerial.o
attempt to open HardwareSerial0.o succeeded
HardwareSerial0.o
attempt to open HardwareSerial1.o succeeded
HardwareSerial1.o
attempt to open HardwareSerial2.o succeeded
HardwareSerial2.o
attempt to open HardwareSerial3.o succeeded
HardwareSerial3.o
attempt to open IPAddress.o succeeded
IPAddress.o
attempt to open PluggableUSB.o succeeded
PluggableUSB.o
attempt to open Print.o succeeded
Print.o
attempt to open Stream.o succeeded
Stream.o
attempt to open Tone.o succeeded
Tone.o
attempt to open USBCore.o succeeded
USBCore.o
attempt to open WMath.o succeeded
WMath.o
attempt to open WString.o succeeded
WString.o
attempt to open abi.o succeeded
abi.o
attempt to open main.o succeeded
main.o
attempt to open new.o succeeded
new.o
attempt to open sketch_uno_blinky.ino.o succeeded
sketch_uno_blinky.ino.o
attempt to open ../config//libgcc.so failed
attempt to open ../config//libgcc.a failed
attempt to open /home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libgcc.so failed
attempt to open /home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libgcc.a succeeded
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libgcc.a)_exit.o
attempt to open ../config//libm.so failed
attempt to open ../config//libm.a failed
attempt to open /home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libm.so failed
attempt to open /home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libm.a failed
attempt to open /home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libm.so failed
attempt to open /home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libm.a succeeded
attempt to open ../config//libc.so failed
attempt to open ../config//libc.a failed
attempt to open /home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libc.so failed
attempt to open /home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libc.a failed
attempt to open /home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.so failed
attempt to open /home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a succeeded
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)dtostrf.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)random.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)atof.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)atol.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)strcpy_P.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)strlen_P.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)itoa.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)itoa_ncheck.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)ltoa.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)ltoa_ncheck.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)mulsi10.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)ultoa.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)ultoa_ncheck.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)utoa.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)utoa_ncheck.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)dtoa_prf.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)strtod.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)ftoa_engine.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)isspace.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)strncasecmp_P.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)strrev.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)cmpsf2.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)floatsisf.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)fp_cmp.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)mulsf3.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)mulsf3x.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)errno.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)cty_isfalse.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)fp_inf.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)fp_nan.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)fp_pscA.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)fp_pscB.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)fp_round.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)fp_split3.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libc.a)fp_zero.o
attempt to open ../config//libatmega328p.so failed
attempt to open ../config//libatmega328p.a failed
attempt to open /home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libatmega328p.so failed
attempt to open /home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libatmega328p.a failed
attempt to open /home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libatmega328p.so failed
attempt to open /home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/../../../../avr/lib/avr5/libatmega328p.a succeeded
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libgcc.a)_divmodsi4.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libgcc.a)_negsi2.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libgcc.a)_copy_data.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libgcc.a)_clear_bss.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libgcc.a)_muluhisi3.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libgcc.a)_mulshisi3.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libgcc.a)_prologue.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libgcc.a)_epilogue.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libgcc.a)_udivmodsi4.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libgcc.a)_umulhisi3.o
attempt to open /tmp/ccAFolcs.ltrans0.ltrans.o succeeded
/tmp/ccAFolcs.ltrans0.ltrans.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libgcc.a)_ctors.o
(/home/kristof/gnu_avr_toolchain/bin/../lib/gcc/avr/7.3.0/avr5/libgcc.a)_tablejump2.o
As you can see, the output mentions the exact location of the linkerscript:
opened script file /home/kristof/gnu_avr_toolchain/avr/bin/../lib/ldscripts/avr5.xn
It even prints the whole content of the file.

Related

Getting "No EOF Marker was found in the PDF file." after using Tesseract C++ API but Tesseract command line utility works fine

I am working on some images using Tesseract & then trying to merge all of the generated PDFs using PoDoFo C++ library.
Have tried 2 approaches (1st one is what I require) :
Using Tesseract C++ API & PoDoFo C++ library
My code is somewhat like this:
For OCR part (run for 001.jpg & 002.jpg):
const char* input_image = "001.jpg";
const char* output_base = "001";
const char* datapath = "/home/test/Desktop/Example2";
int timeout_ms = 5000;
const char* retry_config = nullptr;
bool textonly = false;
tesseract::TessBaseAPI *api = new tesseract::TessBaseAPI();
if (api->Init(datapath, "eng")) {
fprintf(stderr, "Could not initialize tesseract.\n");
exit(1);
}
tesseract::TessPDFRenderer *renderer = new tesseract::TessPDFRenderer(
output_base, api->GetDatapath(), textonly);
bool succeed = api->ProcessPages(input_image, retry_config, timeout_ms, renderer);
if (!succeed) {
fprintf(stderr, "Error during processing.\n");
return EXIT_FAILURE;
}
api->End();
return EXIT_SUCCESS;
For PDF merging part:
void mergePDF(std::vector<char*> inputfiles,char* outputfile) {
try {
/*Reading first PDF */
fprintf(stdout,"Reading file: %s\n",inputfiles[0]);
PoDoFo::PdfMemDocument doc1;
doc1.Load(inputfiles[0]);
/*Reading Second PDF */
fprintf(stdout,"Reading file: %s\n",inputfiles[1]);
PoDoFo::PdfMemDocument doc2;
doc2.Load(inputfiles[1]);
/* Appending doc1 to doc1 */
doc1.Append(doc2);
fprintf(stdout,"Writing files to %s\n ",outputfile);
doc1.Write(outputfile);
}
catch(const PoDoFo::PdfError& e) {
throw e;
}
}
int main(int argc,char* argv[]) {
if (argc < 2) {
printHelp();
exit(EXIT_FAILURE);
}
PoDoFo::PdfError::EnableDebug(false);
std::vector<char*> inputfiles;
char* outputfile;
inputfiles.emplace_back(argv[1]);
inputfiles.emplace_back(argv[2]);
outputfile = argv[3];
try {
mergePDF(inputfiles,outputfile);
}
catch(const PoDoFo::PdfError &e) {
fprintf(stderr,"Error %i occured!\n",e.GetError());
e.PrintErrorMsg();
return e.GetError();
}
exit(EXIT_SUCCESS);
}
Output:
Warning: Invalid resolution 0 dpi. Using 70 instead.
Warning: Invalid resolution 0 dpi. Using 70 instead.
Reading file: /home/test/Desktop/Example2/001.pdf
Error 17 occured!
PoDoFo encountered an error. Error: 17 ePdfError_NoEOFToken
Error Description: No EOF Marker was found in the PDF file.
Callstack:
#0 Error Source: /home/test/podofo/src/podofo/doc/PdfMemDocument.cpp:263
Information: Handler fixes issue #49
#1 Error Source: /home/test/podofo/src/podofo/base/PdfParser.cpp:272
Information: Unable to load objects from file.
#2 Error Source: /home/test/podofo/src/podofo/base/PdfParser.cpp:310
Information: EOF marker could not be found.
#3 Error Source: /home/test/podofo/src/podofo/base/PdfParser.cpp:1528
Using Tesseract command line utility & PoDoFo C++ library
For OCR part, I use Tesseract CLI tool as follows:
tesseract 001.jpg 001 pdf
tesseract 002.jpg 002 pdf
For PDF merging part, the code is same as in point no. 1) above
Output:
Reading file: /home/test/Desktop/Example2/001.pdf
Reading file: /home/test/Desktop/Example2/002.pdf
Fixing references in 13 0 R by 12
Fixing references in 14 0 R by 12
Fixing references in 15 0 R by 12
Fixing references in 16 0 R by 12
Fixing references in 17 0 R by 12
Fixing references in 18 0 R by 12
Fixing references in 19 0 R by 12
Fixing references in 20 0 R by 12
Fixing references in 21 0 R by 12
Fixing references in 22 0 R by 12
Fixing references in 23 0 R by 12
Fixing references in 24 0 R by 12
Reading file: /home/test/Desktop/Example2/output.pdf
I wonder why I am getting the EOF marker issues after using Tesseract C++ API but no such issue after using Tesseract CLI tool.
Am I missing something in the OCR code part in point no. 1) above?

gcov report not showing coverage for functions called within boost::asio::io_service thread

I am using boost::asio::io_service to call the std::thread as shown below..
function:
91 0 : void start_tcp( std::shared_ptr<mapping_t> m_mapping, l_publisher& ll_publisher,
92 : reg_publisher& reg_publisher, std::mutex& mtx, bool debug, const string& host,
93 : uint16_t port, uint16_t maximum_number_of_connections ) {
94 : spdlog::info( "start_tcp debug:{} host:{} port:{} max_connections:{}", debug, host, port,
95 0 : maximum_number_of_connections );
96 0 : modbus_t* ctx = nullptr;
97 0 : if( host == "0.0.0.0" ) {
98 0 : ctx = new_tcp( NULL, port );
99 : } else {
100 0 : ctx = new_tcp( host.c_str(), port );
101 : }
**Above function calling from thread insdie main.cpp:**
: std::thread tcp_thread{start_tcp,
424 : m_mapping,
425 0 : std::ref( l_publisher ),
426 0 : std::ref( reg_publisher ),
427 0 : std::ref( mtx ),
428 : debug_mode,
429 0 : input_file["bindAddress"].as<string>(),
430 0 : input_file["port"].as<unsigned>(),
431 0 : config["maximum-connections"].as<unsigned>()};
432 0 : io_service->run();
When I compile I could see .gcno files are generated. It means, I properly set -g -O0 --coverage compiler flag and then -lgcov linker flag. Also, after the test has run, the .gcda files are generated. But there's no coverage shown for the function start_tcp even though it is executed.
I could see the following been printed to the console when the test has executed; which means this function is executed. But the coverage hasn't shown anything.
spdlog::info( "start_tcp debug:{} host:{} port:{} max_connections:{}", debug,
excerpt from test output:
[2020-03-21 10:41:48.268] [info] start_tcp debug:false host:127.0.0.1 port:1502 max_connections:50\n'
The test is not a unit test, rather it's a functional test written in python (using python sub-process) which validates the command line options of an executable built from the source.
Can someone help me with this problem. Am I doing anything wrong or for boost threads do we need some other special flags if any to get the right coverage report??
I resolved this problem. It is nothing to do with threads. The test is using the executable built from source. Test has spawn the process from executable using pythons subprocess and at the end of the test, this process is terminating using sigterm. But the executable is not handling the sigterm. So no .gcda files been created as explained here...
http://gcc.1065356.n8.nabble.com/gcov-can-t-collect-data-when-process-is-executed-by-systemctl-start-but-it-can-when-executed-by-procs-td1396806.html
By default systemd terminates a service by sending SIGTERM.
(See systemd.kill(5).) If your service doesn't handle it and will just be
killed, it won't produce .gcda file.
Your service should handle SIGTERM and terminate cleanly, like:
void handler(int signum)
{
/* notify the operator that the service has receive SIGTERM
and clean up (close file descriptors, etc). */
exit(0);
}
int main(int argc, char **argv)
{
signal(handler, SIGTERM);
/* do service */
}
enter code here
By using exit(), the functions registered by atexit() and on_exit() would be
called. GCC registers one atexit function to produce .gcda file.
Even if without gcov, it's recommended to catch SIGTERM and terminate your
service cleanly.
After adding code to my main.cpp to handle the sigterm as suggested above. Everything works fine. And I got the proper coverage report.
Thanks.

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

Why can't GCC cross compiler find all libraries?

Why does it look for libgcc in the library search paths, but not for the crt*.o libraries (scroll down in the second code block below)? Also, why is it looking in /lib and /usr/lib under the sysroot, but not in /tmptools/lib under the sysroot (which is the only path that I actually want it to look in)? This is how the cross compiler was configured:
../binutils-2.26/configure --prefix="$LFS_CROSSTOOLCHAIN" --build=$LFS_BUILD_ARCH --host=$LFS_BUILD_ARCH --target=$LFS_TARGET_ARCH --with-lib-path="/tmptools/lib" --disable-multilib --disable-multiarch --disable-rpath --disable-nls --with-sysroot="$LFS_SYSROOT"
../gcc-6.1.0/configure --prefix="$LFS_CROSSTOOLCHAIN" --build=$LFS_BUILD_ARCH --host=$LFS_BUILD_ARCH --target=$LFS_TARGET_ARCH --disable-bootstrap --with-newlib --without-headers --with-local-prefix="/tmptools" --with-native-system-header-dir="/tmptools/include" --with-lib-path="/tmptools/lib" --disable-multilib --disable-multiarch --disable-rpath --enable-languages=c,c++ --disable-nls --with-sysroot="$LFS_SYSROOT"
Where LFS_CROSSTOOLCHAIN=/home/main/lfs/3/crosstools and LFS_SYSROOT=/home/main/lfs/3/root.
This is example output:
$ 3/crosstools/bin/x86_64-lfs-linux-gnu-gcc -print-sysroot
/home/main/lfs/3/root
$ 3/crosstools/bin/x86_64-lfs-linux-gnu-ld -print-sysroot
/home/main/lfs/3/root
$ 3/crosstools/bin/x86_64-lfs-linux-gnu-gcc -Wl,--verbose test.c
GNU ld (GNU Binutils) 2.26.20160125
Supported emulations:
elf_x86_64
elf32_x86_64
elf_i386
elf_iamcu
i386linux
elf_l1om
elf_k1om
using internal linker script:
==================================================
/* Script for -z combreloc: combine and sort reloc sections */
/* Copyright (C) 2014-2015 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-x86-64", "elf64-x86-64",
"elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SEARCH_DIR("=/home/main/lfs/3/crosstools/x86_64-lfs-linux-gnu/lib64"); SEARCH_DIR("/tmptools/lib"); SEARCH_DIR("=/home/main/lfs/3/crosstools/x86_64-lfs-linux-gnu/lib");
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + 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) }
.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.bss .rela.bss.* .rela.gnu.linkonce.b.*)
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
*(.rela.ifunc)
}
.rela.plt :
{
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) *(.iplt) }
.plt.got : { *(.plt.got) }
.plt.bnd : { *(.plt.bnd) }
.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_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 : { *(.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(.init_array.*)))
KEEP (*(.init_array ))
PROVIDE_HIDDEN (__init_array_end = .);
}
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array ))
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) >= 24 ? 24 : 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 ? 64 / 8 : 1);
}
.lbss :
{
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
. = ALIGN(64 / 8);
. = SEGMENT_START("ldata-segment", .);
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
}
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.ldata .ldata.* .gnu.linkonce.l.*)
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
. = 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) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}
==================================================
attempt to open crt1.o failed
attempt to open crti.o failed
attempt to open crtbegin.o failed
attempt to open /tmp/ccLVBgXQ.o succeeded
/tmp/ccLVBgXQ.o
attempt to open /home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/libgcc.so failed
attempt to open /home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/libgcc.a failed
attempt to open /home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/../../../../x86_64-lfs-linux-gnu/lib/libgcc.so failed
attempt to open /home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/../../../../x86_64-lfs-linux-gnu/lib/libgcc.a failed
attempt to open /home/main/lfs/3/root/lib/libgcc.so failed
attempt to open /home/main/lfs/3/root/lib/libgcc.a succeeded
attempt to open /home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/libgcc_s.so failed
attempt to open /home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/libgcc_s.a failed
attempt to open /home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/../../../../x86_64-lfs-linux-gnu/lib/libgcc_s.so failed
attempt to open /home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/../../../../x86_64-lfs-linux-gnu/lib/libgcc_s.a failed
attempt to open /home/main/lfs/3/root/lib/libgcc_s.so failed
attempt to open /home/main/lfs/3/root/lib/libgcc_s.a failed
attempt to open /home/main/lfs/3/root/usr/lib/libgcc_s.so failed
attempt to open /home/main/lfs/3/root/usr/lib/libgcc_s.a failed
attempt to open /home/main/lfs/3/root/home/main/lfs/3/crosstools/x86_64-lfs-linux-gnu/lib64/libgcc_s.so failed
attempt to open /home/main/lfs/3/root/home/main/lfs/3/crosstools/x86_64-lfs-linux-gnu/lib64/libgcc_s.a failed
attempt to open /tmptools/lib/libgcc_s.so failed
attempt to open /tmptools/lib/libgcc_s.a failed
attempt to open /home/main/lfs/3/root/home/main/lfs/3/crosstools/x86_64-lfs-linux-gnu/lib/libgcc_s.so failed
attempt to open /home/main/lfs/3/root/home/main/lfs/3/crosstools/x86_64-lfs-linux-gnu/lib/libgcc_s.a failed
attempt to open /home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/libc.so failed
attempt to open /home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/libc.a failed
attempt to open /home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/../../../../x86_64-lfs-linux-gnu/lib/libc.so failed
attempt to open /home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/../../../../x86_64-lfs-linux-gnu/lib/libc.a failed
attempt to open /home/main/lfs/3/root/lib/libc.so failed
attempt to open /home/main/lfs/3/root/lib/libc.a failed
attempt to open /home/main/lfs/3/root/usr/lib/libc.so failed
attempt to open /home/main/lfs/3/root/usr/lib/libc.a failed
attempt to open /home/main/lfs/3/root/home/main/lfs/3/crosstools/x86_64-lfs-linux-gnu/lib64/libc.so failed
attempt to open /home/main/lfs/3/root/home/main/lfs/3/crosstools/x86_64-lfs-linux-gnu/lib64/libc.a failed
attempt to open /tmptools/lib/libc.so failed
attempt to open /tmptools/lib/libc.a failed
attempt to open /home/main/lfs/3/root/home/main/lfs/3/crosstools/x86_64-lfs-linux-gnu/lib/libc.so failed
attempt to open /home/main/lfs/3/root/home/main/lfs/3/crosstools/x86_64-lfs-linux-gnu/lib/libc.a failed
attempt to open /home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/libgcc.so failed
attempt to open /home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/libgcc.a failed
attempt to open /home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/../../../../x86_64-lfs-linux-gnu/lib/libgcc.so failed
attempt to open /home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/../../../../x86_64-lfs-linux-gnu/lib/libgcc.a failed
attempt to open /home/main/lfs/3/root/lib/libgcc.so failed
attempt to open /home/main/lfs/3/root/lib/libgcc.a succeeded
attempt to open /home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/libgcc_s.so failed
attempt to open /home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/libgcc_s.a failed
attempt to open /home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/../../../../x86_64-lfs-linux-gnu/lib/libgcc_s.so failed
attempt to open /home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/../../../../x86_64-lfs-linux-gnu/lib/libgcc_s.a failed
attempt to open /home/main/lfs/3/root/lib/libgcc_s.so failed
attempt to open /home/main/lfs/3/root/lib/libgcc_s.a failed
attempt to open /home/main/lfs/3/root/usr/lib/libgcc_s.so failed
attempt to open /home/main/lfs/3/root/usr/lib/libgcc_s.a failed
attempt to open /home/main/lfs/3/root/home/main/lfs/3/crosstools/x86_64-lfs-linux-gnu/lib64/libgcc_s.so failed
attempt to open /home/main/lfs/3/root/home/main/lfs/3/crosstools/x86_64-lfs-linux-gnu/lib64/libgcc_s.a failed
attempt to open /tmptools/lib/libgcc_s.so failed
attempt to open /tmptools/lib/libgcc_s.a failed
attempt to open /home/main/lfs/3/root/home/main/lfs/3/crosstools/x86_64-lfs-linux-gnu/lib/libgcc_s.so failed
attempt to open /home/main/lfs/3/root/home/main/lfs/3/crosstools/x86_64-lfs-linux-gnu/lib/libgcc_s.a failed
attempt to open crtend.o failed
attempt to open crtn.o failed
/home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/../../../../x86_64-lfs-linux-gnu/bin/ld: cannot find crt1.o: No such file or directory
/home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/../../../../x86_64-lfs-linux-gnu/bin/ld: cannot find crti.o: No such file or directory
/home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/../../../../x86_64-lfs-linux-gnu/bin/ld: cannot find crtbegin.o: No such file or directory
/home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/../../../../x86_64-lfs-linux-gnu/bin/ld: cannot find -lgcc_s
/home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/../../../../x86_64-lfs-linux-gnu/bin/ld: cannot find -lc
/home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/../../../../x86_64-lfs-linux-gnu/bin/ld: cannot find -lgcc_s
/home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/../../../../x86_64-lfs-linux-gnu/bin/ld: cannot find crtend.o: No such file or directory
/home/main/lfs/3/crosstools/lib/gcc/x86_64-lfs-linux-gnu/6.1.0/../../../../x86_64-lfs-linux-gnu/bin/ld: cannot find crtn.o: No such file or directory
collect2: error: ld returned 1 exit status
When I built a GCC toolchain for cross-compiling ARM, I used this helpful tutorial. The errors you are seeing look similar to what happens if you skip these commands:
make -j4 csu/subdir_lib
install csu/crt1.o csu/crti.o csu/crtn.o /opt/cross/aarch64-linux/lib
Which are part of a sequence of commands used to provide the headers for GLIBC to the cross-compiler.
mkdir -p build-glibc
cd build-glibc
../glibc-2.20/configure --prefix=/opt/cross/aarch64-linux --build=$MACHTYPE
--host=aarch64-linux --target=aarch64-linux \
--with-headers=/opt/cross/aarch64-linux/include \
--disable-multilib libc_cv_forced_unwind=yes
make install-bootstrap-headers=yes install-headers
make -j4 csu/subdir_lib
install csu/crt1.o csu/crti.o csu/crtn.o /opt/cross/aarch64-linux/lib \
aarch64-linux-gcc -nostdlib -nostartfiles -shared -x c /dev/null -o \
/opt/cross/aarch64-linux/lib/libc.so
touch /opt/cross/aarch64-linux/include/gnu/stubs.h
cd ..
It's unclear if the GLIBC headers are already in your sysroot directory, but I would start by checking to make sure those files exist. You may need to build the GLIBC headers if you are not getting them some other way.

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?