Why should "data = .;" be repeated three times in a linker script? - linker

I saw this link script in
http://www.jamesmolloy.co.uk/tutorial_html/1.-Environment%20setup.html
SECTIONS
{
.text 0x100000 :
{
code = .; _code = .; __code = .; // What is this line for?
*(.text)
. = ALIGN(4096);
}
.data :
{
data = .; _data = .; __data = .;
*(.data)
*(.rodata)
. = ALIGN(4096);
}
.bss :
{
bss = .; _bss = .; __bss = .;
*(.bss)
. = ALIGN(4096);
}
end = .; _end = .; __end = .;
}
You can see that, code, _code, __code and the fallowing ones all appearing in a same style. What are they for? Why should they be written in such a way?

The syntax <symbol> = . simply defines a symbol at the current address.
You can use this symbol like this:
extern int __code;
int foo()
{
cout << "Address of __code" << &__code << endl;
}
_code and __code typically holds the start address of the text section. This is used from the startup code of your system you compile for.
Definig symbols without a leading underscore are not so common I believe. This can maybe result in conflicts with normal definitions from your code. But this is only a convention. Technically you can define what you want and need. The rules are the same as all other symbols in your project: Never define symbols twice :-)

Related

Why are zero-initialized globals defined outside of bss using this linker script?

I have the following two variables, KMEM_END and MEM_TOP:
extern char _kernel_mem_end[];
extern char _physical_mem_end[];
uint64_t KMEM_END;
uint64_t MEM_TOP;
void kmem_init()
{
kprintf("\nkmem_end: %p\n", (uint64_t) _kernel_mem_end);
kprintf("phys_top: %p\n", (uint64_t) _physical_mem_end);
kprintf("&KMEM_END: %p\n", &KMEM_END);
kprintf("&MEM_TOP: %p\n", &MEM_TOP);
// ...
}
I have _kernel_mem_end and _physical_mem_end provided by the linker script, here:
OUTPUT_ARCH("riscv");
ENTRY(start);
MEMORY {
/* The -kernel QEMU option copies the image to that specific address. */
ram (wxa) : ORIGIN = 0x80000000, LENGTH = 128M
}
SECTIONS {
/* Starts at the address 0x80000000. */
.text : ALIGN(4K) {
PROVIDE(_text_start = .);
*(.init)
*(.text .text.*)
. = ALIGN(4K);
PROVIDE(_text_end = .);
} >ram
.data : ALIGN(4K) {
PROVIDE(_data_start = .);
*(.data .data.*)
. = ALIGN(16);
*(.sdata .sdata.*)
. = ALIGN(4K);
PROVIDE(_data_end = .);
} >ram
.rodata : ALIGN(4K) {
PROVIDE(_rodata_start = .);
*(.rodata .rodata.*)
. = ALIGN(16);
*(.srodata .srodata.*)
. = ALIGN(4K);
PROVIDE(_rodata_end = .);
} >ram
.bss : ALIGN(4K) {
PROVIDE(_bss_start = .);
*(.bss .bss.*)
. = ALIGN(4K);
PROVIDE(_stack_start = .);
. += 0x10000;
PROVIDE(_stack_end = .);
PROVIDE(_bss_end = .);
} >ram
. = ALIGN(4K);
PROVIDE(_kernel_mem_end = .);
PROVIDE(_physical_mem_end = ORIGIN(ram) + LENGTH(ram));
}
As the variables are globals and uninitialized (default-initialized to zero), I expect them to reside in the BSS section. However, the output of kmem_init is as follows:
kmem_end: 80015000
phys_top: 88000000
&KMEM_END: 80015008
&MEM_TOP: 80015000
This means that the two variables reside between _kernel_mem_end and _physical_mem_end, which is not a "standard" section at all (most importantly, not bss.)
I get them to reside in the data section by initializing them to something other than zero, and that's fine for my purpose. I can initialize them to whatever as I will just override the initial value. However, I want to know why does this happen?
Using --orphan-handling=error while invoking ld, I found out that .sbss existed in the object file, but was never included in the unified final executable.
So using *(.bss .bss.* .sbss .sbss.*) instead of *(.bss .bss.*) fixed the issue.

size of a input section GNU ld

How do you get the size of an input section in ld? I would assume its just SIZEOF(.section); however ld gives an error upon trying to run that. Is there any way I can do this? .section would be defined in a .asm file like so
section .section
mov al, 15
Here's the linker script I have so far:
SECTIONS {
boot : {
*( .boot );
. += SECTOR_SIZE - SIZEOF( .boot_header );
*( .boot_header );
}
}
I have no problem with SIZEOF.
Just tested:
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
_datasize = SIZEOF(.data);
Works as expected.

Compile a function to run it in other machine without resolving address dependencies

Im developing a bare metal OS for raspberry pi 1. The main idea of this OS is a simply kernel that will be able to run a function created in other machine and send it to the raspi. The function will use functions that were compilated with the kernel and that reside in memory.
I want to know how can I compile a function that when I will insert the payload in memory in a determinated address it will be able to call system functions and use the data that are defined in the function code.
void function()
{
while (1)
{
uart_puts("Hello\r\n");
}
}
This is my link.ld file and the function will be loaded at __binary_function:
ENTRY(_start)
SECTIONS
{
/* Starts at LOADER_ADDR. */
. = 0x8000;
__start = .;
__text_start = .;
.text :
{
KEEP(*(.text.boot))
*(.text)
}
. = ALIGN(4096); /* align to page size */
__text_end = .;
__rodata_start = .;
.rodata :
{
*(.rodata)
}
. = ALIGN(4096); /* align to page size */
__rodata_end = .;
__data_start = .;
.data :
{
*(.data)
}
. = ALIGN(4096); /* align to page size */
__data_end = .;
__bss_start = .;
.bss :
{
bss = .;
*(.bss)
}
. = ALIGN(4096); /* align to page size */
__bss_end = .;
/*Allocating memory for the heap*/
__heap_start = .;
. = . + 0x1000000; /*4MB Heap section*/
__heap_end = .;
__binary_function = .;
__end = .;
}
My idea is that the kernel will receive the payload via UART and then execute it. The payload must be able to call system functions such us the UART functions and access to the data that is define inside it.
I want to do this automatically with arm-none-eabi-gcc (GCC Toolchain for ARM architecture) that works like GCC and avoiding harcoding the system functions in the payload source.
Thanks!
I solve it using the hardcoding the kernel functions in the payload:
void (* uart_puts)(char *) = (void(*)(char * )) 0x0000000000008248;
I get the 0x0000000000008248 address from the .map file generated in the compilation of the kernel.

How to put all static variables coming from a static library in a specific linker script section

I'm working on a stm32 nucleo board. My project is composed of several different libraries.
I would like to put all uninitialized variables coming from static library (mylib.a) in a specific memory section instead of the bss section.
Here is my bss section inside the linker script:
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
I tried adding this section before the bss one:
. = ALIGN(4);
.mybss :
{
/* This is used by the startup in order to initialize the .bss section */
_smybss = .; /* define a global symbol at bss start */
__mybss_start__ = _smybss;
mylib.a:*(.bss)
mylib.a:*(.bss*)
mylib.a:*(COMMON)
. = ALIGN(4);
_emybss = .; /* define a global symbol at bss end */
__mybss_end__ = _emybss;
} >RAM
The compiler does not complain but when I inspect with nm command the generated elf _smybss symbol is at the same address of _emybss symbol. So mybss section is empty.
Do you have any suggestion on how to achive this?
Thanks

Splitting embedded program in multiple parts in memory

I am working on an embedded system (Stellaris Launchpad) and writing a simple OS (as a hobby project). The used toolchain is gcc-none-eabi.
My next step is to get used to the MPU to allow the kernel to prevent user programs from altering specific data. I have a bunch of C files and I splitted them in two parts: kernel and other.
I have the following linker script to start out with:
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000
SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000
}
SECTIONS
{
.text :
{
_text = .;
KEEP(*(.isr_vector))
*(.text*)
*(.rodata*)
_etext = .;
} > FLASH
.data : /*AT(ADDR(.text) + SIZEOF(.text))*/ /*contains initialized data*/
{
_data = .;
*(vtable)
*(.data*)
_edata = .;
} > SRAM AT > FLASH
.bss : AT (ADDR(.data) + SIZEOF(.data)) /*contains unitialized data (should be set to all zero's)*/
{
_bss = .;
*(.bss*)
*(COMMON)
_ebss = .;
_start_heap = .;
} > SRAM
_stack_top = ORIGIN(SRAM) + LENGTH(SRAM) - 1; /*The starting point of the stack, at the very bottom of the RAM*/
}
And after reading up on linker scripts I know that I can replace the stars with filenames, and thus start splitting the flash in multiple parts. I would for example create a .kernel.bss section and put all of the kernel object files instead of the stars in that section.
My only problem left is that the kernel is not one file, it is a whole lot of files. And files might be added, removed etc. So how do I do this? How do I change my linker script so that a dynamic first group of files is mapped to the first place and a dynamic second group of files is mapped to a second place?
you know that you can specify what files are used as input for a section?
We use this for separating kernel and application code into fast internal flash, and slower external flash memory, like so:
.kernel_text :
{
build/kernel/*.o (.text*) /*text section from files in build/kernel*/
} > INT_FLASH
.app_text:
{
build/app/*.o(.text*)
} > EXT_FLASH
Section 4.6.4 might be helpful, (describes input sections in more detail)
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/4/html/Using_ld_the_GNU_Linker/sections.html
I found a solution, allthough it feels a bit hacky. It does work though:
I found out that a linker script is OK with working on .a files if they are statically linked with ar. So lets say you have a buch of .o files that, together form the kernel: a.o, b.o, c.o. Use ar rcs kernel.a a.o, b.o, c.o. kernel.a is now your kernel, which you want to store seperately in memory.
The next thing you need to know is that the * in a linker script is actually a wildcard for everything not used yet. So we can create the following linker script:
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000
SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000
}
SECTIONS
{
.kernel.text :
{
_kernel_text = .;
KEEP(kernel.a(.isr_vector))
KEEP(kernel.a(_sbrk))
kernel.a(.text*)
kernel.a(.rodata*)
_kernel_etext = .;
_kernel_flash_data = ALIGN(0x4);
} > FLASH
.kernel.data : /*AT(ADDR(.text) + SIZEOF(.text))*/ /*contains initialized data*/
{
_kernel_data = .;
kernel.a(vtable)
kernel.a(.data*)
_kernel_edata = .;
} > SRAM AT > FLASH
.kernel.bss :
{
_kernel_bss = .;
kernel.a(.bss*)
kernel.a(COMMON)
_kernel_ebss = .;
} > SRAM
.text : /*AT (ADDR(.core.text) + SIZEOF(.core.text) + SIZEOF(.core.data))*/
{
_text = .;
*(.text*)
*(.rodata*)
_etext = .;
_flash_data = ALIGN(0x4);
} > FLASH
.data :
{
_data = .;
*(vtable)
*(.data*)
_edata = .;
} > SRAM AT > FLASH
.bss : AT (ADDR(.data) + SIZEOF(.data)) /*contains unitialized data (should be set to all zero's)*/
{
_bss = .;
*(.bss*)
*(COMMON)
_ebss = .;
_start_heap = .;
} > SRAM
}
This works but will probably lead to a new problem: the linker treats libraries as.. well, libraries. So if they contain the program start (as in my case) the linker does not actually look for it, the linker only looks trough the library for functions refered to by the actual o files. The solution I found for this is to add the -u <name> flag to the linker invocation. This flag causes a symbol to become undefined, so the linker will look for this symbol plus all symbols that are needed by this synbol.
My invocation, for references sake:
arm-none-eabi-ld -Tlinker_script.ld -nostdlib --entry ResetISR
--gc-sections -u _sbrk -u .isr_vector
-L./lib//hardfp
-L/home/me/gcc-arm-none-eabi/gcc-arm-none-eabi-4_9-2015q1/arm-none-eabi/lib/armv7e-m/fpu
-L/home/me/gcc-arm-none-eabi/gcc-arm-none-eabi-4_9-2015q1/lib/gcc/arm-none-eabi/4.9.3/armv7e-m/fpu
-Lrelease/
-o release/os
./user/obj/release/ledsDance.c.o ./user/obj/release/main.c.o ./validation/obj/release/val_floattest.c.o ./validation/obj/release/val_genTest.c.o ./validation/obj/release/val_gpiotest.c.o ./validation/obj/release/val_iotest.c.o ./validation/obj/release/val_proctest.c.o ./validation/obj/release/val_schedTest.c.o release/kernel.a release/core.a
-ldriver-cm4f
-luartstdio
-lm
-lc
-lgcc

Resources