How to use ld --gc-sections with OUTPUT_FORMAT(binary) - linker

If my GNU ld linker script has OUTPUT_FORMAT(binary) the ld --gc-sections command-line flag seems to be ignored:
$ cat gcs.c
extern void magic(void);
void callmagic(void) { magic(); }
int uanswer = 42;
int main(void) { return 0; }
$ cat ofbin.scr
OUTPUT_FORMAT(binary)
OUTPUT_ARCH(i386)
ENTRY(main)
SECTIONS {
. = 0x10000;
.text : { *(.text*) }
.data : { *(.data*) *(.rodata*) }
.bss : { *(.bss*); }
}
$ cat ofelf.scr
OUTPUT_FORMAT(elf32-i386)
OUTPUT_ARCH(i386)
ENTRY(main)
SECTIONS {
. = 0x10000;
.text : { *(.text*) }
.data : { *(.data*) *(.rodata*) }
.bss : { *(.bss*); }
}
$ gcc -m32 -nostdlib -nostartfiles -nodefaultlibs gcs.c -ffunction-sections -fdata-sections -Wl,--gc-sections,--print-gc-sections -Wl,-T,ofelf.scr
/usr/bin/ld: Removing unused section '.text.callmagic' in file '/tmp/ccSFoPYg.o'
/usr/bin/ld: Removing unused section '.data.uanswer' in file '/tmp/ccSFoPYg.o'
/usr/bin/ld: Removing unused section '.eh_frame' in file '/tmp/ccSFoPYg.o'
$ gcc -m32 -nostdlib -nostartfiles -nodefaultlibs gcs.c -ffunction-sections -fdata-sections -Wl,--gc-sections,--print-gc-sections -Wl,-T,ofbin.scr
/tmp/cceXCw2b.o: In function `callmagic':
gcs.c:(.text.callmagic+0x7): undefined reference to `magic'
collect2: error: ld returned 1 exit status
I'm using GNU ld 2.24 and GCC 4.8.4 on Ubuntu 14.04.
How can I make this .c file compile and link with OUTPUT_FORMAT(binary) and with the code of callmagic eliminated by --gc-sections?

It looks like this is impossible, and GNU ld ignores --gc-sections with OUTPUT_FORMAT(binary).
A possible workaround is using OUTPUT_FORMAT(elf32-i386) and post-processing the output ELF file, e.g. with objcopy -O binary a.out a.out.bin.

Related

[Golang][Cgo] It is possible to build go source file with c-archive with less runtime libraries?

I have one question about export golang source file as c-archive file when building. For example, we have 2 files for both c and golang.
// The Entry defined in golang, and build with cgo.
extern void Entry();
int main() {
// Entry();
return 0;
}
package main
import "C"
//export Entry
func Entry(magic int) {
}
//#cgo CFLAGS: -nostdlib -nostdinc -fno-builtin -fno-stack-protector -m32 -Wall -Wextra -Werror
func main() {
}
For c source files, it may be compiled like below.
gcc -nostdlib -nostdinc -fno-builtin -fno-stack-protector -m32 -Wall -Wextra -Werror -c entry/main.c -o entry/main.o
For golang source files, it will be compiled like below.
go build -o entry/entry.a -buildmode=c-archive entry/entry.go
After that, we would like to link it together as below. Unfortunately, it may depend on some more symbols from libc or even more libs from cgo.
ld -T./config/link.ld -m elf_i386 entry/main.o entry/entry.a -o unicorn/kernel
ld: entry/entry.a(000010.o): in function `x_cgo_thread_start':
/_/runtime/cgo/gcc_util.c:15: undefined reference to `malloc'
ld: /_/runtime/cgo/gcc_util.c:18: undefined reference to `stderr'
ld: entry/entry.a(000010.o): in function `fprintf':
/usr/include/bits/stdio2.h:105: undefined reference to `fwrite'
ld: entry/entry.a(000010.o): in function `x_cgo_thread_start':
/_/runtime/cgo/gcc_util.c:19: undefined reference to `abort'
ld: entry/entry.a(000005.o): in function `fatalf':
/_/runtime/cgo/gcc_fatalf.c:17: undefined reference to `stderr'
ld: entry/entry.a(000005.o): in function `fprintf':
/usr/include/bits/stdio2.h:105: undefined reference to `fwrite'
ld: entry/entry.a(000005.o): in function `vfprintf':
/usr/include/bits/stdio2.h:135: undefined reference to `__vfprintf_chk'
ld: entry/entry.a(000005.o): in function `fprintf':
/usr/include/bits/stdio2.h:105: undefined reference to `fputc'
ld: entry/entry.a(000005.o): in function `fatalf':
/_/runtime/cgo/gcc_fatalf.c:22: undefined reference to `abort'
ld: unicorn/kernel: hidden symbol `__stack_chk_fail_local' isn't defined
ld: final link failed: bad value
I am not sure for now if it is possible to compile the golang source files with fewer links to libc or cgo libraries. Here is the link.ld for reference. Thank you very much.
ENTRY(start)
OUTPUT_FORMAT("elf32-i386")
SECTIONS
{
.text 0x100000 :
{
code = .; _code = .; __code = .;
*(.text)
. = ALIGN(4096);
}
.data :
{
data = .; _data = .; __data = .;
*(.data)
*(.rodata)
. = ALIGN(4096);
}
.bss :
{
bss = .; _bss = .; __bss = .;
*(.bss)
. = ALIGN(4096);
}
end = .; _end = .; __end = .;
}

Line numbers in GCC output object file not preserved when linking to ELF

I am trying to build a basic project for ARM with symbols and associated line numbers, so that I can easily debug the project from GDB Multiarch while it is running in QEMU.
I have two files, a C source file and some assembly. In this example, they are very simple:
cmain.c:
int add_numbers(int a, int b) {
return a + b;
}
int cmain() {
int a = 3;
int b = 4;
int c = add_numbers(a, b);
}
main.s:
.section .init
.global _start
_start:
.extern cmain
mov sp, #0x8000
bl cmain
Additionally, here's the linker file, kernel.ld:
SECTIONS {
.init 0x8000 : {
*(.init)
}
.text : {
*(.text)
}
.data : {
*(.data)
*(.bss)
*(.rodata*)
*(.COMMON)
}
/DISCARD/ : {
*(*)
}
}
I then build these projects with debugging symbols using the following shell script. In brief, it assembles and compiles the files into object files, then links them into an ELF and objcopies into an IMG.
rm -r build
mkdir -p build
arm-none-eabi-as -I . main.s -o build/main.o
arm-none-eabi-gcc -ffreestanding -fno-builtin -march=armv7-a -MD -MP -g -c cmain.c -o build/cmain.o
arm-none-eabi-ld build/main.o build/cmain.o -L/usr/lib/gcc/arm-none-eabi/6.3.1/ -lgcc --no-undefined -o build/output.elf -T kernel.ld
arm-none-eabi-objcopy build/output.elf -O binary build/kernel.img --keep-file-symbols
For GDB debugger stepping, I need the ELF to have line numbers for the C source. (Note that the actual project has many more C files.) The lines numbers are present in C object file, but not in the ELF.
$ arm-none-eabi-nm build/cmain.o --line-numbers
00000000 T add_numbers /home/aaron/Desktop/arm-mcve/cmain.c:1
00000030 T cmain /home/aaron/Desktop/arm-mcve/cmain.c:5
$ arm-none-eabi-nm build/output.elf --line-numbers
00008008 T add_numbers
00008038 T cmain
00008000 T _start
Why is there no line number information in the ELF, and how can I add it so that GDB can step through it?
Your linker script discards the sections with debugging information. Look at the default linker script arm-none-eabi-ld --verbose for some ideas. You will at least need some of the DWARF 2 sections:
.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) }
(Adding all of them should work.)

undefined reference to `calloc' when linking with arm-none-eabi-ld

I'm encountering an error that is doubtless due to some limit of my knowledge on how linkers work. Some ANSI C code I've written that compiles and links perfectly well on my OS X box fails to link with arm-none-eabi-ld when cross-compiled for ARM.
Here's the result from a clean make (with --verbose on ld):
arm-none-eabi-gcc -o build/fft.o src/fft.c -g -mthumb -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -Os -ffunction-sections -fdata-sections -MD -std=c99 -Wall -pedantic -DPART_TM4C123GH6PM -c -I../tivaware -DTARGET_IS_BLIZZARD_RA1
arm-none-eabi-gcc -o build/main.o src/main.c -g -mthumb -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -Os -ffunction-sections -fdata-sections -MD -std=c99 -Wall -pedantic -DPART_TM4C123GH6PM -c -I../tivaware -DTARGET_IS_BLIZZARD_RA1
arm-none-eabi-ld -o build/a.out build/fft.o build/main.o --verbose -T TM4C123GH6PM.ld --entry main --gc-sections
GNU ld (32-bit ARM EABI Toolchain JBS-FLOAT_IO-SGXXLITE_ML-2014.05-28-v2013.05-36-g3f93944) 2.24.51.20140217
Supported emulations:
armelf
opened script file TM4C123GH6PM.ld
using external linker script:
==================================================
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000
SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0X00008000
}
SECTIONS
{
/* code */
.text :
{
_text = .;
/* ensure ISR vectors are not removed by linker */
KEEP(*(.isr_vector))
*(.text*)
*(.rodata*)
_etext = .;
} > FLASH
/* static data */
.data : AT(ADDR(.text) + SIZEOF(.text))
{
_data = .;
*(vtable)
*(.data*)
_edata = .;
} > SRAM
/* static uninitialized data */
.bss :
{
_bss = .;
*(.bss*)
*(COMMON)
_ebss = .;
} > SRAM
}
==================================================
attempt to open build/fft.o succeeded
build/fft.o
attempt to open build/main.o succeeded
build/main.o
build/fft.o: In function `dft':
/path/src/fft.c:97: undefined reference to `calloc'
There's a number of other undefined symbols (__aeabi_dadd, __muldc3), which I've truncated for brevity.
Microcontrollers usually (practical reasons) are not configured with dynamic memory allocation facility.
so, malloc, calloc, free will not be available.
Recommendation: use static array to allocate memory.
even after reading this you need dynamic memory allocation, you can use newlibc
but beware that in case your heap and stack overlap, you will be in problem.

LD giving strange error and not finding an existing file when using ARM gcc

This is the command line executed by my Makefile:
arm-none-eabi-gcc bubblesort.c -O0 -mcpu=cortex-m0 -mthumb -Wl, -T ../boot_and_link/linker.ld -l ../boot_and_link/startup.o
As I understand it, it should compile bubblesort.c for a CortexM0 and then the linker should you use linker.ld as a linker script and should also link startup.o with the output of compiling bubblesort.c.
I get two errors:
/usr/lib/gcc/arm-none-eabi/4.8/../../../arm-none-eabi/bin/ld: cannot find : No such file or directory
/usr/lib/gcc/arm-none-eabi/4.8/../../../arm-none-eabi/bin/ld: cannot find -l../boot_and_link/startup.o
The first one I don't understand. ld tells me it cannot find : which makes no sense and makes me think there an error in my linker script.
The second error is just weird because my linker file is in the exact same location and it finds it and yes I've checked the file's names and they are the same.
Just in case I'm including my linker script on account of it being short and that I wrote it myself (first time) and I'm learning how to write them.
MEMORY
{
rom : ORIGIN = 0x00000000, LENGTH = 8K
ram : ORIGIN = 0x20004000, LENGTH = 16K
stack : ORIGIN = 0x20003FFF, LENGTH = 16K
}
SECTIONS
{
.nvic_vector : { } >rom /*The vector table that is initialized in c code*/
.text :
{
*(.text)
/*_DATAI_BEGIN = .;*/
} >rom
.data :
{
_DATA_LOAD = LOADADDR(.data); /*The absolute address of the data section*/
_DATA_BEGIN = .; /*From where to begin the copy to RAM*/
*(.data)
. = ALIGN(4); /*Make sure the byte boundary is correctly aligned*/
_DATA_END = .; /*Where to end the copy to RAM*/
} >ram AT >rom
.bss :
{
_BSS_BEGIN = .; /* Zero-filled run time allocate data memory */
*(.bss)
_BSS_END = .;
} > ram
.heap :
{
_HEAP = .;
} > ram
.stack :
{
. += LENGTH(stack);
. = ALIGN(4);
_STACKTOP = .; /* The top of the stack is the last available section of memory*/
} >stack
}
Any help would be appreciated.
You could separate compilation and linking, then it's easier to see
flags common both for compiler and linker
flags only for one of these
If you have main.c and startup.c, compilation should look like this:
arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -mfloat-abi=soft -Os -std=gnu99 -o startup.o -c startup.c
arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -mfloat-abi=soft -Os -std=gnu99 -o main.o -c main.c
As for linking
arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -mfloat-abi=soft -nostartfiles -T rom.ld -o main.elf startup.o main.o -lc -lm
If you want it in a single line:
arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -mfloat-abi=soft -Os -std=gnu99 -nostartfiles -T rom.ld -o main.elf startup.c main.c
So the main problem was this line:
arm-none-eabi-gcc bubblesort.c -O0 -mcpu=cortex-m0 -mthumb -Wl, -T ../boot_and_link/linker.ld -l ../boot_and_link/startup.o
This was wrong as the -l switched is used to link with a library and not to just point another object file which was my intention. You need to specify all files for linking as normal ordinary arguments to the linker. The way I ended up doing this was simply (taking Beryllium's advice) separating the compilation and linking into two steps and using two separate calls. Here are the commands that are run by my makefile:
<-------------------- Compiling C Source Files -------------------->
arm-none-eabi-gcc -O0 -c -mcpu=cortex-m0 -mthumb -g bubblesort.c -o bubblesort.o
<-------------------- Linking files -------------------->
arm-none-eabi-ld bubblesort.o ../boot_and_link/startup.o -nostartfiles -T ../boot_and_link/linker.ld -o bubblesort.elf
This worked.
PD: The first error (wher it says it cannot find : No such file or directory) had to to with incorrect spacing in the gcc call. However as I changed it, I cannot exactly recall where it was.

Linker script undefined reference to PUTS

I'm trying to learn linker script
Here are my files
caller.c
extern void hello();
void main()
{
hello();
}
helloasm.c
#include <stdio.h>
void hello()
{
printf("\nHELLO\n\n");
}
link.lds
SECTIONS
{
. = 0x10000;
.text : { *(.text) }
. = 0x8000000;
.data : { *(.data) }
.bss : { *(.bss) }
}
compile.sh
cc -S helloasm.c #generate assembly file
cc -c helloasm.s #generate object file
cc -c caller.c #generate object file
ld -o hello -T link.lds helloasm.o caller.o
when i'm using
cc caller.c helloasm.c
i'm getting the output
HELLO
but when the sh file is called
i'm getting error
**
helloasm.o: In function `hello':
helloasm.c:(.text+0xe): undefined reference to `puts'
**
can someone explain why puts function is undefined
GNU ld (GNU Binutils for Ubuntu) 2.23.2
gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-1ubuntu1)

Resources