GCC -T link option issue - gcc

I have compiled the project with arm-none-eabi-gcc to object with command
arm-none-eabi-gcc --specs=nosys.specs -mcpu=cortex-m7 -mtune=cortex-m7 -Os -g -gdwarf-2 -c $< -o $(#)
currently I got the object file when I try to link it with command in object foler
arm-none-eabi-gcc --specs=nosys.specs -mcpu=cortex-m7 -mtune=cortex-m7 -g -gdwarf-2 -nostartfiles -T ..\project.ld -o target *
However I got some strange error
arm-none-eabi/bin/ld.exe: error: no memory region specified for loadable section `.text.memcmp'
I understand that when I use -T option the link script file will be used instead of default link script. it looks like the section definitions for some builtin function are missing. I tried to fix that put
.text.memcmp : {*(.text.memcmp)}
in my ld file, it looks like this section is fixed however I got another error:
arm-none-eabi/bin/ld.exe: error: no memory region specified for loadable section `.text.memset'
so I don't think put .text.memset in the LD file is correct fix, because after I put `.text.memset' in ld file , I got another error :
arm-none-eabi/bin/ld.exe: error: no memory region specified for loadable section `.text._snprintf_r'
I think I missed some options in GCC to create these default sections for builtin functions
What is the root cause of this issue and how to fix that? Thank you so much!
Update: Add the LD file below :
MEMORY {
INIT_SRAM : ORIGIN = 0x34400000, LENGTH = 0x1FB000
INIT_SRAM_NO_CACHEABLE : ORIGIN = 0x3460A000, LENGTH = 0x1DF00
INIT_SRAM_STACK : ORIGIN = 0x34628000, LENGTH = 0x15000
RAM_RSVD : ORIGIN = ., LENGTH = 0
BOOT_TEST : ORIGIN = 0x43840000 LENGTH = 0x50
}
SECTIONS
{
.boot_test : {*(.boot_test)}> BOOT_TEST
.exception_table ALIGN(4) : > {*(.exception_table)}>INIT_SRAM
.startup ALIGN(4) : {*(.startup)}
.ramcode ALIGN(4) : > {*(.ramcode)}
.text ALIGN(4) : { *(.text) }
.ramcode ALIGN(4) : { *(.ramcode) }
.rodata ALIGN(4) : { *(.rodata) }
.data ALIGN(4) : { *(.data) }
.bss ALIGN(16) : { *(.bss) }
_TEST_SESSION_START = .;
.TEST_SESSION :{*(.TEST_SESSION)}
_TEST_SESSION_END = (. - 1);
_Stack_start = .;
__STACK_SIZE = SIZEOF(INIT_SRAM_STACK);
__RAM_NO_CACHEABLE_START = ADDR(INIT_SRAM_NO_CACHEABLE);
}

Changing
.text ALIGN(4) : { *(.text) }
to
.text ALIGN(4) : { *(.text) *(.text.*) }
can fix this .text.xxx missing issue.

Related

How do i set up data memory address when using "riscv32/64-unknown-elf-gcc"?

I designed RISCV32IM processor, and i used "riscv32/64-unknown-elf-gcc" to generate code for test.
Instruction memory setting has been solved with the options below(-Ttext option), but data memory setting has not been solved yet.
riscv64-unknown-elf-gcc -v -march=rv32im -mabi=ilp32 -nostartfiles -x c -Ttext 40000000 -o main.o main.c
Can I know if I can set the data memory address I want?
looks like you need to link linker script, something like:
OUTPUT_ARCH( "riscv" )
ENTRY(_start)
SECTIONS
{
. = 0x40000000;
.text.init : { *(.text.init) }
. = ALIGN(0x1000);
.text : { *(.text) }
. = ALIGN(0x1000);
.data : { *(.data) }
.bss : { *(.bss) }
_end = .;
}
_start is a start symbol and 0x40000000 is a memory start address,
followed by the section names aligned by 0x1000.
text this is the program itself
data is a statically initialized variables
bss
is a statically allocated variables

undefined reference to _GLOBAL_OFFSET_TABLE_ (only when generating binaries)

this is the problem:
When I link my scripts in C, using ld, when I generate elf32-i386 files as output format in ld, putting it as OUTPUT_FORMAT() in the ld script, I dont have any error, but if I try to put in this last OUTPUT_FORMAT() "binary" or try to output a file with .bin extension, I get a mixture of errors like:
kernel.o: In function `k_main':
kernel.c:(.text+0xe): undefined reference to `_GLOBAL_OFFSET_TABLE_'
kernelutils.o: In function `k_clear_screen':
kernelutils.c:(.text+0xc): undefined reference to `_GLOBAL_OFFSET_TABLE_'
kernelutils.o: In function `k_clear_screen_front':
kernelutils.c:(.text+0x56): undefined reference to `_GLOBAL_OFFSET_TABLE_'
kernelutils.o: In function `k_printf':
kernelutils.c:(.text+0xa0): undefined reference to `_GLOBAL_OFFSET_TABLE_'
kernelutils.o: In function `k_sleep_3sec':
kernelutils.c:(.text+0x152): undefined reference to `_GLOBAL_OFFSET_TABLE_'
kernelmalloc.o:kernelmalloc.c:(.text+0xc): more undefined references to `_GLOBAL_OFFSET_TABLE_' follow
This not only happens when compiling specific scripts, all scripts that try to use ld to link, or gcc since this calls ld, die in the attempt of get a binary with .bin extension.
When showing the symbols of one of the executables (kernel.o in the output of above) I see that the symbol _GLOBAL_OFFSET_TABLE_ isnt defined, and the most scary part, all the functions that returned error in the error output of above have their symbols removed, this is the nm output:
cristian#mymethodman:~/Desktop/kernel/0.0.3/Archivos$ nm kernel.o
U _GLOBAL_OFFSET_TABLE_
U k_clear_screen
U k_clear_screen_front
00000000 T k_main
U k_malloc
U k_printf
U k_sleep_3sec
00000000 T __x86.get_pc_thunk.bx
How I can solve this? I will leave the linker script below to ensure it isn a problem of the .ld file, with both "to get elf" and "to get binary" versions. Thanks in advance!
Ld scripts:
To get binary:
ENTRY(loader)
OUTPUT_FORMAT(binary)
SECTIONS {
/* The kernel will live at 3GB + 1MB in the virtual
address space, which will be mapped to 1MB in the
physical address space. */
. = 0xC0100000;
.text : AT(ADDR(.text) - 0xC0000000) {
*(.text)
*(.rodata*)
}
.data ALIGN (0x1000) : AT(ADDR(.data) - 0xC0000000) {
*(.data)
}
.bss : AT(ADDR(.bss) - 0xC0000000) {
_sbss = .;
*(COMMON)
*(.bss)
_ebss = .;
}
}
To get ELF:
ENTRY(loader)
OUTPUT_FORMAT(elf32-i386)
SECTIONS {
/* The kernel will live at 3GB + 1MB in the virtual
address space, which will be mapped to 1MB in the
physical address space. */
. = 0xC0100000;
.text : AT(ADDR(.text) - 0xC0000000) {
*(.text)
*(.rodata*)
}
.data ALIGN (0x1000) : AT(ADDR(.data) - 0xC0000000) {
*(.data)
}
.bss : AT(ADDR(.bss) - 0xC0000000) {
_sbss = .;
*(COMMON)
*(.bss)
_ebss = .;
}
}
As yo ucan see between both only changes the OUTPUT_FORMAT() line.
Your toolchain probably defaults to generating position-independent executables (PIE). Try compiling with gcc -fno-pie.
If you want to keep PIE for security reasons, you'll need a more complicated linker script and something that performs the initial relocation (such as a dynamic linker, but simpler constructions are possible as well).

How to convert a GNU linker Script ld to Scatter File (ARM)

I would like to migrate from GCC to the new ARM COMPILER 6.
But I'm not able to well convert the Gnu liker script (ld) to the equivalent of ARM Scatter file.
The Original Code is as following:
arm-none-eabi-ld -T link.ld test.o shared/bootcode.o shared/vertors.o -o test.elf
Where link.ld script is as following
ENTRY(bootcode)
SECTIONS
{
. = 0x00000000;
/* Code starts with vectors, then bootcode, then other code */
.text :
{
*vectors.o(vectors)
*bootcode.o(boot)
*(.text) /* remainder of code */
} =0
.data : { *(.data) }
.bss : { *(.bss) }
/* Notes section
* This is not used so we discard it. Although not used it needs to be
* explicitly mentioned in the linker script as some toolchains will place
* the notes section at adderss 0 if it is not explicitly mentioned*/
/DISCARD/ : { *(.note*) }
}
I would like to use armlink as a linker :
armlink --cpu=8-A.32 --entry=bootcode test.o shared/bootcode.o shared/vertors.o -o test.elf --scatter=ld.scat
But I did not succeed in Creating a valid scatter File. I tried to play with the armlink options (--first, --last, --ro_base, --rw_base) but nothing went as expected (I'm getting successful compilation but the test is not working).
Any Idea on that please?
I looked at the documentation here: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0803d/pge1362065973150.html
The GNU Linker Script you want to migrate can be rewritten as:
LOAD_ROM 0x0000
{
EXEC_ROM_1 0x0000 ; Name of first exec region (EXEC_ROM_1),
; Start address for exec region (0x0000)
{
vectors.o(VECTORS)
* (InRoot$$Sections) ; All library sections that must be in a
; root region, for example, __main.o,
; __scatter*.o, __dc*.o, and * Region$$Table
}
EXEC_ROM_2 +0 ; Name of second exec region (EXEC_ROM_2)
{
bootcode.o(BOOT, +FIRST)
* (+RO)
}
SRAM +0 ; Name of third exec region (SRAM)
{
* (+RW, +ZI) ; Place all RW and ZI data into
; this exec region
}
}
In order to specify the entry point of your image you can use the command line option --entry=bootcode as you already specified in your command line.
armlink --cpu=8-A.32 --entry=bootcode test.o shared/bootcode.o shared/vertors.o -o test.elf --scatter=ld.scat
armlink allows reading of GNU LD linker script, however, with restrictions.
The flag is "--linker_script=ld_script".

Actual default linker script and settings gcc uses

Where can I find the actual linker script and settings gcc uses?
Things I've tried:
For concreteness, let's consider a small program:
empty.c
int main(void)
{
return 0;
}
build it statically, and look at the result:
$ gcc -static -o empty empty.c
$ readelf -W -l empty
Elf file type is EXEC (Executable file)
Entry point 0x400f4e
There are 6 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x0bf581 0x0bf581 R E 0x200000
LOAD 0x0bfeb0 0x00000000006bfeb0 0x00000000006bfeb0 0x001d80 0x0042d8 RW 0x200000
NOTE 0x000190 0x0000000000400190 0x0000000000400190 0x000044 0x000044 R 0x4
TLS 0x0bfeb0 0x00000000006bfeb0 0x00000000006bfeb0 0x000020 0x000058 R 0x10
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
GNU_RELRO 0x0bfeb0 0x00000000006bfeb0 0x00000000006bfeb0 0x000150 0x000150 R 0x1
Section to Segment mapping:
Segment Sections...
00 .note.ABI-tag .note.gnu.build-id .rela.plt .init .plt .text __libc_freeres_fn __libc_thread_freeres_fn .fini .rodata __libc_subfreeres __libc_atexit __libc_thread_subfreeres .eh_frame .gcc_except_table
01 .tdata .init_array .fini_array .jcr .data.rel.ro .got .got.plt .data .bss __libc_freeres_ptrs
02 .note.ABI-tag .note.gnu.build-id
03 .tdata .tbss
04
05 .tdata .init_array .fini_array .jcr .data.rel.ro .got
Note the various sections, grouped into segments, and placed into memory regions of various permissions.
Now let's attempt to get as much information as possible on how it did this linking.
$ gcc -static -o empty empty.c -Wl,--verbose
GNU ld (GNU Binutils for Ubuntu) 2.24
Supported emulations:
elf_x86_64
elf32_x86_64
elf_i386
i386linux
elf_l1om
elf_k1om
i386pep
i386pe
using internal linker script:
==================================================
/* Script for -z combreloc: combine and sort reloc sections */
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
"elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SEARCH_DIR("/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/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) }
.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) >= 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_*) }
}
==================================================
... <snip searching and linking actual object files>
But the script, while long, is missing most of the import information previously listed.
How does it know which sections to gather into different load segments?
There is no PHDRS command, and while the use of SEGMENT_START suggests there are some standard segments for this system defined somewhere else, none of the sections are listed with an associated segment.
Furthermore, how does it know where to load these segments, or what permissions these memory regions have?
There is no MEMORY command. And again, if there are some standard memory regions for this system defined somewhere else, none of the sections list which memory region to use.
When I've seen default linker scripts before for microcontrollers, they were incredibly detailed. This output however suggests there are more scripts and settings somewhere.
Where are these other linker script definitions and settings stored?
Well, I know that this is an old question, but I also found it frustrating that there is no precise info about options that are used during the linking process. This answer shows my journey to find them.
First of all, I was looking into official docs https://gcc.gnu.org/onlinedocs/ - I searched the GCC Manual and GCC Internals Manual. The only meaningful information that I found is that gcc uses an internal tool called collect2 to invoke the linker. According to https://gcc.gnu.org/onlinedocs/gccint/Collect2.html "The program collect2 works by linking the program once and looking through the linker output file for symbols with particular names indicating they are constructor functions". So it's used to make linking possible.
Next thing that I tried is getting through source code. You can browse code here https://code.woboq.org/gcc/gcc/collect2.c.html . The problem is that it wasn't really helpful. But I noticed that collect2 fork_execute function to invoke ld. You can deep dive into fork_execute to find out that it will fork (execute a new program in the forked program) and wait for it to finish. Because both forks and execs are system calls (to put it quickly - system calls are the way/functions the application uses to communicate with a system). I decided to give it a try.
So I made the simple program that doesn't require any compilation (it's already compiled to object file - so everything that gcc have to do is linking).
[Alex#Normandy tmp]$ gcc hello.c.s -o hello_gcc
[Alex#Normandy tmp]$ ./hello_gcc
Hello, World!
Then I use strace with following options:
-o forked.log save the output to forked.log
-s 1024 variables shorter than 1024 chars are not truncated (default 32 was not enough)
-f - enables strace on forked processes
-e trace=/exec - filter system calls so only ones starting with exec are shown
The final output was following.
[Alex#Normandy tmp]$ strace -o forked.log -s 1024 -f -e trace=/exec gcc hello.c.s -o hello_gcc
[Alex#Normandy tmp]$ grep 'ld' forked.log
2153 execve("/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2", ["/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2", "--build-id", "--no-add-needed", "--eh-frame-hdr", "--hash-style=gnu", "-m", "elf_x86_64", "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2", "-o", "hello_gcc", "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o", "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o", "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o", "-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5", "-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64", "-L/lib/../lib64", "-L/usr/lib/../lib64", "-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../..", "/tmp/ccyl36jf.o", "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed", "-lc", "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed", "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o", "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o"], 0x17b9da0 /* 61 vars */) = 0
2154 execve("/usr/bin/ld", ["/usr/bin/ld", "--build-id", "--no-add-needed", "--eh-frame-hdr", "--hash-style=gnu", "-m", "elf_x86_64", "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2", "-o", "hello_gcc", "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o", "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o", "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o", "-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5", "-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64", "-L/lib/../lib64", "-L/usr/lib/../lib64", "-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../..", "/tmp/ccyl36jf.o", "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed", "-lc", "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed", "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o", "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o"], 0x7fff14226a98 /* 61 vars */) = 0
So used ld command was
/usr/bin/ld --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o hello_gcc /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../.. /tmp/ccyl36jf.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o
So what the f*** was made? Well, all options can be found in the manual. Here is decomposed output.
/usr/bin/ld - linker program
--build-id - add build-id to binary. In my system default it is sha1.
--no-add-needed - it is depracaceted name for --no-copy-dt-needed-entries - it is connected with DT_NEEDED tags inside ELF, if I get that correctly it means that DT_NEEDED tag won't be copied from input libraries.
--eh-frame-hdr - "Request creation of ".eh_frame_hdr" section and ELF "PT_GNU_EH_FRAME" segment header." Whatever that means.
--hash-style=gnu - "Set the type of linker's hash table(s)." Default is sysv, but there is a newer format gnu. Binary can also have a hash table(s) in both formats.
-m elf_x86_64 - linkers emulates (makes elf type binary for x86_64)
-dynamic-linker /lib64/ld-linux-x86-64.so.2 - set name of expected dynamic linker
-o hello_gcc - set output binary
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o - code that is run before main of actual program
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o- code that is run before main of actual program
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o - code that is run before main of actual program
-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 - additional library search path
-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64 - additional library search path
-L/lib/../lib64 - additional library search path
-L/usr/lib/../lib64 - additional library search path
-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../.. - additional library search path
/tmp/ccyl36jf.o - this is actual program (binary object) with it's main function
-lgcc - -l option - "Add the archive or object file specified by namespec to the list of files to link." In that case it is gcc.
--as-needed - enable "as-needed" mode that checks if on particular point following library (namespace?) is needed
-lgcc_s - add gcc_s note that only if it's really needed at this moment.
--no-as-needed - disable "as-needed" mode that checks if on particular point following library (namespace?) is needed
-lc- standard C namespace/library
-lgcc - this lib should be already set. There might be something between this and previous usage of this option.
--as-needed - set "as-needed mode. There might be something between this and previous usage of this option.
-lgcc_s - already described. There might be something between this and previous usage of this option.
--no-as-needed -- disable "as-needed mode".
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o - additional code that run when program finish
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o - additional code that run when program finish.
More about: crt1.o, crti.o, crtbegin.o, crtend.o, crtn.o - they are startup, initialization, constructor, destructor and finalization files (according to Building Embedded Linux Systems By Karim Yaghmour).
Probably simpler way
During writing this answer I also "discovered" that you can invoke gcc with -v option and it will return COLLECT_GCC_OPTIONS, that is identical to invoked ld
COLLECT_GCC_OPTIONS='-v' '-o' 'hello_gcc' '-mtune=generic' '-march=x86-64'
/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2 --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o hello_gcc /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../.. hello_gcc.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o
Still, if you want to be sure for 100% how ld was invoked - the strace is your best bet.
Lastly, note that I used Enterprise Linux v7 and v8 system to check if I'm right. Both of them uses the x86_64 arch, and the results might be different on different architectures.
On my Ubuntu system, the linker scripts are located at:
/lib/x86_64-linux-gnu/ldscripts
The base script appears to be chosen based on the target architecture, such as elf_x86_64, and the for each base architecture there are several variants.
I am not sure, but the variant appears to be chosen based on certain linker options.

Relocate specific object files of a library

I have a GCC project for ARM Cortex-M3. The linker script defines where each source section has to be located. So I have sections like this
.text :
{
*(.text)
} > FLASH
_sidata = .;
.data : AT (_sidata)
{
_sdata = .;
*(.data)
_edata = .;
}
The project consumes the library lib.a that contains the object file object.o and other.o. Now I want that the .text section of object.o shall be placed between _sdata and _edata. The objectiv is that these section would be copied by the startup code from the FLASH to RAM and it will be executed there. The other.o shall not be placed in that section since it's too large.
I tried it like in this SO question
.data : AT (_sidata)
{
_sdata = .;
*(.data)
object.o(.text)
_edata = .;
}
But this fails since the object.o is taken from a library and is not direct available.
I found it by myself. The library must be specififed.
.data : AT (_sidata)
{
_sdata = .;
*(.data)
lib.a:object.o(.text)
_edata = .;
}

Resources