I am new to GNU compiler.
I have a C source code file which contains some structures and variables in which I need to place certain variables at a particular locations.
So, I have written a linker script file and used the __ attribute__("SECTION") at variable declaration, in C source code.
I am using a GNU compiler (cygwin) to compile the source code and creating a .hex file using -objcopy option, but I am not getting how to link my linker script file at compilation to relocate the variables accordingly.
I am attaching the linker script file and the C source file for the reference.
Please help me link the linker script file to my source code, while creating the .hex file using GNU.
/*linker script file*/
/*defining memory regions*/
MEMORY
{
base_table_ram : org = 0x00700000, len = 0x00000100 /*base table area for BASE table*/
mem2 : org =0x00800200, len = 0x00000300 /* other structure variables*/
}
/*Sections directive definitions*/
SECTIONS
{
BASE_TABLE : { } > base_table_ram
GROUP :
{
.text : { } { *(SEG_HEADER) }
.data : { } { *(SEG_HEADER) }
.bss : { } { *(SEG_HEADER) }
} > mem2
}
C source code:
const UINT8 un8_Offset_1 __attribute__((section("BASE_TABLE"))) = 0x1A;
const UINT8 un8_Offset_2 __attribute__((section("BASE_TABLE"))) = 0x2A;
const UINT8 un8_Offset_3 __attribute__((section("BASE_TABLE"))) = 0x3A;
const UINT8 un8_Offset_4 __attribute__((section("BASE_TABLE"))) = 0x4A;
const UINT8 un8_Offset_5 __attribute__((section("BASE_TABLE"))) = 0x5A;
const UINT8 un8_Offset_6 __attribute__((section("SEG_HEADER"))) = 0x6A;
My intention is to place the variables of section "BASE_TABLE" at the address defined i the linker script file and the remaining variables at the "SEG_HEADER" defined in the linker script file above.
But after compilation when I look in to the .hex file the different section variables are located in different hex records, located at an address of 0x00, not the one given in linker script file .
Please help me in linking the linker script file to source code.
Are there any command line options to link the linker script file, if any plese provide me with the info how to use the options.
Thanks in advance,
SureshDN.
Try gcc -Xlinker -T (linker script name) (c sources files)
I first compile all my c files to object files and then link them with:
gcc -Xlinker -T"xxx.lds" (all object files)
From The gcc docs:
`-Xlinker OPTION'
Pass OPTION as an option to the linker. You can use this to
supply system-specific linker options which GNU CC does not know
how to recognize.
Thanks for the response ,
I have found one more linker option in GCC ,"ld" and teh option -T to link the sections to the source code.
ld -T (linker scriptname) -o (final objfile) (objectfile of source file)
Thanks
Suresh
Related
In my config.ini file I have defined these variables:
# Where will system be loaded when started (for which address to prepare it)
LOAD_ADDR = 0x100000
RAM_ADDR = 0x300000
ROM_ADDR = 0x200000
STACK_ADDR = 0x600000
Which I then use in the .data section of the linker script ldscript.ld:
SECTIONS {
.code LOAD_ADDR :
{ /* This is line 9 */
kernel_code_addr = .;
/* instructions */
*?/boot/startup.asm.o ( .text* )
*( .text* )
}
.data RAM_ADDR : AT(ROM_ADDR)
{
kernel_data_addr = .;
/* read only data (constants), initialized global variables */
* ( .rodata* .data* )
}
.bss :
{
*( .bss* COMMON* )
. = ALIGN (4096);
}
/* ... */
}
But running make fails while linking with this error:
[linking build/04_Debugging.elf]
ld:build/ldscript.ld:9: non constant or forward reference address expression for section .data
make: *** [Makefile:87: build/04_Debugging.elf] Error 1
When I replace RAM_ADDR and ROM_ADDR in the code with their values, make finishes nicely and everything works.
What causes this error? Why can I use LOAD_ADDR with no errors?
The linker does not seem to load the variables you defined in config.ini.
You can use INCLUDE in your linker script to include another file.
From https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_chapter/ld_3.html
INCLUDE filename
Include the linker script filename at this point. The file will be searched for in the current directory, and in any directory specified with the -L option. You can nest calls to INCLUDE up to 10 levels deep.
So if you add INCLUDE config.ini to the start of your linker script it should work.
Another approach is to use the C preprocessor to generate your linker script.
You can use -imacros to load a config.h that defines the symbols you want, then use them in the linkerscript.ld.h and generate the linker script before using it to link
gcc -imacros config.h -E linkerscript.ld.h -o linkerscript.ld
is there a way to use regex to add all C object files starting with foo for example to the linker file bss section with Windriver compiler instead of adding them manually one by one
SECTIONS {
outputa 0x10000 :
{
foo1.o (.bss)
foo2.o (.bss)
......
foon.o (.bss)
}
Imagined solution
SECTIONS {
outputa 0x10000 :
{
foo*.o (.bss)
Yes, it is possible to use regex in linker script.
GROUP : {
.sectionname:{"foo*"(.bss) }
....
}
How to fail the build based on the conditional values of linker variables defined in linker script?
I am compiling C code using GCC. I defined a linker variable BINARY_TEST. If Value of BINARY_TEST > 32KB, then i want to Fail the build. How to write a conditional test and fail the build using linker script?
Please suggest any script.
SECTIONS
{
. = 0x0000 ;
.text :
{
*(.text)
*(.rdata)
}
.data :
{
*(*.data)
*(*.bss)
}
BINARY_TEST = . ;
/*Want something like below */
if (BINARY_TEST > 32KB)
Throw Error and stop
/* ******* */
END = . ;
}
How to write a conditional test and fail the build using linker script?
It seems to me that you could trivially implement the failure as a post-link step. E.g. in your Makefile:
foo.exe: foo.o
$(CC) -o foo.exe ...
nm foo.exe | grep BINARY_TEST | \
... commands to verify that symbol value < 32K, or fail
Here is one way to do this:
CHECK_BOOTLOADER_SIZE = 1 / (. <= 32768);
If the current position is beyond the limit, this will give an error message:
linker.ld:33 / by zero
Not the clearest error message but at least it includes the line number so that user can read the comments.
I need to create an application to extract one file from zip archive, after which I want to compile it for Android.
I'm using Ubuntu, with libzip-0.10.1 pre-installed.
I created C project in Eclipse, added include path and found simple script for extracting file. Unfortunately I cannot get the following to build and I could use some advice.
// zip.c file
#include <stdio.h>
#include <stdlib.h>
#include <zip.h>
int main(int argc, char **argv) {
struct zip *zip_file;
struct zip_file *file_in_zip;
int err;
int files_total;
int file_number;
int r;
char buffer[10000];
if (argc < 3) {
fprintf(stderr,"usage: %s <zipfile> <fileindex>\n",argv[0]);
return -1;
};
zip_file = zip_open(argv[1], 0, &err);
if (!zip_file) {
fprintf(stderr,"Error: can't open file %s\n",argv[1]);
return -1;
};
file_number = atoi(argv[2]);
files_total = zip_get_num_files(zip_file);
if (file_number > files_total) {
printf("Error: we have only %d files in ZIP\n",files_total);
return -1;
};
file_in_zip = zip_fopen_index(zip_file, file_number, 0);
if (file_in_zip) {
while ( (r = zip_fread(file_in_zip, buffer, sizeof(buffer))) > 0) {
printf("%s",buffer);
};
zip_fclose(file_in_zip);
} else {
fprintf(stderr,"Error: can't open file %d in zip\n",file_number);
};
zip_close(zip_file);
return 0;
};
Also I added few .h files to include directory in my project and few .c files to directory with zip.c file. After that all dependences was good, but I have an error:
‘struct zip’ has no member named ‘default_password’ in file zip_fopen_index.c
The file zip_fopen_index.c is:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "zipint.h"
ZIP_EXTERN struct zip_file *
zip_fopen_index(struct zip *za, zip_uint64_t fileno, int flags)
{
return zip_fopen_index_encrypted(za, fileno, flags, za->default_password); // error here
}
First of all allow me some comments:
Your program is not compiled and linked by Eclipse.
Compiling is done by the compiler (gcc using option -c):
make all
Building file: ../zip.c
Invoking: GCC C Compiler
gcc -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"zip.d" -MT"zip.d" -o "zip.o" "../zip.c"
Finished building: ../zip.c
Linking is done by the linker (via the compiler using option -o):
Invoking: GCC C Linker
gcc -o "unzipper" ./zip.o
./main.o: In function `zip':
/home/alk/workspace/unzipper/Debug/../zip.c:20: undefined reference to `zip_open'
/home/alk/workspace/unzipper/Debug/../zip.c:27: undefined reference to `zip_get_num_files'
/home/alk/workspace/unzipper/Debug/../zip.c:33: undefined reference to `zip_fopen_index'
/home/alk/workspace/unzipper/Debug/../zip.c:35: undefined reference to `zip_fread'
/home/alk/workspace/unzipper/Debug/../zip.c:38: undefined reference to `zip_fclose'
/home/alk/workspace/unzipper/Debug/../zip.c:43: undefined reference to `zip_close'
collect2: ld returned 1 exit status
Eclipse provides a framework helping you in managing all sources and their references as also spawing compiler and linker tasks and setting their options.
When the linker told you there where undefined references to the zip_*function during the build of your program, the cause for this was, you were missing to tell the linker (via the compiler, via Eclipse) where those zip_* functions could be found.
Those zip_* functions are located in a library, namely libzip.
So what you as the programmer need to tell the linker (via the compiler, via Eclipse) is to link those functions against what the compiler compiled from your sources.
As the result the linker is able to create a runnable program from your compiled sources together with all libraries needed. Certain libraries are know to Eclipse (and therfore to the linker) by default, for example the one containing the C standard functions, namely libc.
To get things going:
1 Remove the source files you pulled from the libzip librarie's sources from your project. Those sources had been compiled into the library libzip, which you will use in your project.
2 Tell the linker (via Eclipse) to use libzip for your project.
Do so by following the steps below:
open the project's properties
click 'C/C++ General'
click 'Path and Symbols', on the left select the 'Libraries' tab, there click 'Add' and enter zip
finally click 'OK'
3 Then try to build your program:
Building target: unzipper
Invoking: GCC C Linker
gcc -o "unzipper" ./zip.o -lzip
Finished building target: unzipper
(Please note additional option -lzip!)
If the developement version of 'libzip' had been installed properly before, you should be fine.
PS: unzipper was the name I used for the Eclispe project to produce the examples.
PSS: I used Eclipse Juno SR1
How can I make static libraries with only binary data, that is without any object code, and make that data available to a C program? Here's the build process and simplified code I'm trying to make work:
./datafile:
abcdefghij
Makefile:
libdatafile.a:
ar [magic] datafile
main: libdatafile.a
gcc main.c libdatafile.a -o main
main.c:
#define TEXTPTR [more magic]
int main(){
char mystring[11];
memset(mystring, '\0', 11);
memcpy(TEXTPTR, mystring, 10);
puts(mystring);
puts(mystring);
return 0;
}
The output I'm expecting from running main is, of course:
abcdefghijabcdefghij
My question is: what should [magic] and [more magic] be?
You can convert a binary file to a .o file using objcopy; the generated file then defines symbols for the start address, end address and size of the binary data.
objcopy -I binary -O elf32-little data data.o
The data can be referenced from a program via
extern char const _binary_data_start[];
extern char const _binary_data_end[];
The data lives between those two pointers (note that declaring them as pointers does not work).
The "elf32-little" part needs to be adapted according to your target platform. There are many other options for fine control over the processing.
Put the data in global variables.
char const text[] = "abcdefghij";
Don't forget to declare text in a header. If the data is currently in a file, the FreeBSD file2c tool can convert it to C source code for you (manpage).