Can I use Preprocessor Directives in .ld file - c

Can I use Preprocessor Directives in .ld file?
I need to to use one of two sets of .ld file and wants to let Build engine deside that using macro, Can I do that?

Yes, you can. You need to run preprocessor manually for your linker script, like this:
in="your_linker_script.ld"
out="generated_script.ld"
cflags=-Iinclude/
gcc -E -P -x c $cflags $in >$out
Flags:
-E specifies GCC to only run preprocessor
-P prevents preprocessor from generating linemarkers (#line directives)
-x c tells GCC to treat your linker script as C source file (it's needed to run GCC with your LD script)
Or you can simply use cpp tool, which is actually C preprocessor.
After this you will be able to use generated linker script to build your program (e.g. in Makefile).
Example
Here is how I solved this problem in my project:
Here is my linker script uses preprocessor (#include directive and CONFIG_TEXT_BASE constant). Excerpt:
#include <config.h>
. = CONFIG_TEXT_BASE;
Here is script to generate preprocessed linker script. Excerpt:
gcc -E -P -x c -Iinclude $cflags $in >>$out
Here is my Makefile, it's generating preprocessed linker script at $(LDS_GEN) target (line 53) and the this generated script is being used to build result binary (line 42). Excerpt:
$(LDS_GEN): $(LDS)
build/gen-lds.sh $(LDS) $(LDS_GEN) $(CFLAGS)
$(APP).bin: $(OBJS) $(LDS_GEN)
$(LD) $(OBJS) -T $(LDS_GEN) -o $(APP).elf

Small update after long time. This way of pre-processing works until the memory file does not contain lines that are fooling the pre-processor. E.g.:
"KEEP(*path/*.o(.rodata .rodata*))"
The "/*" after path is considered comment start (the line contains what is considered a C multi-line comment start and not a match pattern).
This line is valid for the linker but it is considered comment and the output from C pre-processor will remove everything till a supposed closing comment is found:
"KEEP(*path"
The resulting file is clearly invalid for the linker. I have no solution at the moment.

As a simplification of Sam's answer, I added the below to my makefile and away we go :)
PRE_LD_FILE = $(PROG_NAME).ld
LD_FILE = $(PROG_NAME)_generated.ld
$(LD_FILE) : $(PRE_LD_FILE)
cpp $(PRE_LD_FILE) | grep -v '^#' >>$(LD_FILE)

Related

How to include header files with E-ACSL wrapper script?

I am new to Frama-C and wanted to ask how I could add header files when using the E-ACSL wrapper script. Normally, I've been adding header files the following way with WP and RTE:
frama-c -rte main.c -cpp-extra-args="-I src/include -I ..."
However, I am unsure of how I can include these files when using the wrapper script.
e-acsl-gcc.sh --rte=all -c main.c
Without the header files I run into the following error:
[kernel] Parsing main.c (with preprocessing)/main.c:10:10: fatal error: header.h: No such file or directory #include "header.h"
I am using Frama-C 24.0 (Chromium). Any help would be appreciated. Thanks.
If you run e-acsl-gcc.sh -h, you'll get a help message with the script's options:
Options:
-h show this help page
-c compile instrumented code
(...)
-E pass additional arguments to the Frama-C preprocessor
-F pass additional options to the Frama-C command line
(...)
The two above are relevant for you: -E adds arguments to an implicit -cpp-extra-args used by the script, while -F allows you to add the option itself.
So, you can either run:
e-acsl-gcc.sh -E "-Isrc/include -I..." <other options and source files>
Or:
e-acsl-gcc.sh -F -cpp-extra-args="-Isrc/include,-I..." <other options and source files>
Note that with -F, due to quoting issues (between e-acsl-gcc.sh, Frama-C's command-line, C preprocessor, etc), you may need to replace spaces with commas, as in "-Isrc/include,-I...".
Important: do not add spaces between -I and the directory name. Due to parsing issues, e-acsl-gcc.sh will not parse it correctly if you do. GCC accepts both syntaxes anyway, so I'd recommend getting used to not adding spaces after -I (and -D as well) in general.
Overall, using -E is better here, but -F can be used to pass other options besides -cpp-extra-args.

Pass variable from C file to makefile

In my makefile, I added parameters to linker flags as a variable BOOTLOAD
LDFLAGS += -Wl,--section-start=.bootloader=$(BOOTLOAD)
If i write BOOTLOAD = 0x3800 in makefile everything is working fine.
But i want to pass this variable from C code, so i tried to define it like #define BOOTLOAD 0x3800. But the linker cannot find it.
How should i pass BOOTLOAD from C file?
Instead of "passing" the macro from a C source file (which is possible but not easy), you could instead ask the preprocessor to define the macro when compiling with the -D option:
gcc -DBOOTLOAD=$(BOOTLOAD) -c source_file.c
I recommend you check the GCC preprocessor command line option reference for more information about the -D option.
It is possible to search a specific source file to the macro definition and then set a makefile variable to the extracted value, but it's easier to do it the other way around as shown above.
It seems you have to grep BOOTLOAD from the source code in your makefile as follows:
BOOTLOAD = $(shell grep '#\s*define\s\+BOOTLOAD' YOUR_SOURCE_FILE | awk 'print $3')
LDFLAGS += -Wl,--section-start=.bootloader=$(BOOTLOAD)

C/C++ file before preprocessing

Is it possible to look at a c/c++ file before preprocessing? Or rather after just a half-hearted pre-processing? Basically there is a
#define <commonly_used_word> 0
in a third party library header and I want to figure out where it is. So basically, I just want the compiler to include all the headers but not the the preprocessor as such.
Your original source file is file before preprocessing.
It sounds like you want your #include directives processed, yet you want to keep macros non-substituted. Both actions are carried out by the preprocessor.
In general case it is impossible, since in C and C++ it is legal to use macros as include file names, as in
#define INCLUDE_FILE "stdio.h"
#include INCLUDE_FILE
Achieving what you want would require a preprocessor specifically designed to satisfy your request. I, for one, don't know of any such preprocessor implementation.
If you want to find where a specific macro is defined, you might try the following trick: define your own macro with the same name before including any headers, and start compilation. The compiler (the preprocessor) should complain about macro redefinition when it encounters the library definition of the same macro and point out its location to you.
There are GCC-specific -M and -MM options:
To list absolute paths of include files, use -M
Instead of outputting the result of preprocessing, output a rule
suitable for make describing the dependencies of the main source file.
The preprocessor outputs one make rule containing the object file name
for that source file, a colon, and the names of all the included
files, including those coming from -include or -imacros command line
options. gcc -M test.c
If you dont want the system includes like
#include <stdio.h>,
then use -MM Like -M but do not mention header files that are found in
system header directories, nor header files that are included,
directly or indirectly, from such a header. gcc -MM test.c
That could significantly narrow down the search area.
http://www.math-linux.com/spip.php?article263
You can tell cpp to generate the list of included files using -M option:
$ cpp -M a.c
a.o: a.c /usr/include/stdio.h /usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/bits/wordsize.h \
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.1/include/stddef.h \
/usr/include/bits/types.h /usr/include/bits/typesizes.h \
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h \
/usr/lib/gcc/x86_64-pc-linux-gnu/4.7.1/include/stdarg.h \
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
It gives you a Makefile rule format but you could ignore that and use with any other command.
For example, you can grep for the symbol (here I'm ignoring stderr because of \ and a.o: not being a real file names -- laziness):
$ grep '#\s*define\s*BUFSIZ' $(cpp -M a.c) 2>/dev/null
/usr/include/stdio.h:# define BUFSIZ _IO_BUFSIZ
You can also use a program like ctags to find the symbol for you:
$ ctags $(cpp -M a.c)
...
$ grep BUFSIZ tags
BUFSIZ /usr/include/stdio.h 128;" d
If you know which header files contain the definition you're looking for, e.g by using find and grep as suggested, you may be able to pinpoint which one is affecting the current source file by getting gcc to print the header inclusion tree. As described in gcc's documentation, you can achieve this by using the -H option, possibly combined with -MG to eliminate normal processing.

How to compile a program of c Language manually on MS DOS instead of Borland

I need to compile a program in MS DOS. I have Borland Editor, I can compile it using Alt+F9 but the things is what it do at the backend. I want to compile it in MS DOS. I m trying this:
c:\tc\bin>tcc -o hello.exe hello.c
where hello.c is is my file, hello.exe the file I want to produce. Its not working, what shouldI do? and also please tell me also how do I compile .cpp file manually from MS DOS.
If I remember correctly, Borland/Turbo C compiler's command line options didn't look like gcc options. You should try tcc /? for a command line help.
Turbo C++ Version 3.00 Copyright (c) 1992 Borland International
Syntax is: TCC [ options ] file[s] * = default; -x- = turn switch x off
-1 80186/286 Instructions -2 80286 Protected Mode Inst.
-Ax Disable extensions -B Compile via assembly
-C Allow nested comments -Dxxx Define macro
-Exxx Alternate Assembler name -G Generate for speed
-Ixxx Include files directory -K Default char is unsigned
-Lxxx Libraries directory -M Generate link map
-N Check stack overflow -O Optimize jumps
-P Force C++ compile -Qxxx Memory usage control
-S Produce assembly output -Txxx Set assembler option
-Uxxx Undefine macro -Vx Virtual table control
-X Suppress autodep. output -Yx Overlay control
-Z Suppress register reloads -a Generate word alignment
-b * Treat enums as integers -c Compile only
-d Merge duplicate strings -exxx Executable file name
-fxx Floating point options -gN Stop after N warnings
-iN Max. identifier length -jN Stop after N errors
-k Standard stack frame -lx Set linker option
-mx Set Memory Model -nxxx Output file directory
-oxxx Object file name -p Pascal calls
-r * Register variables -u * Underscores on externs
-v Source level debugging -wxxx Warning control
-y Produce line number info -zxxx Set segment names
C:\TC\BIN>
So, I think you should type:
tcc hello.c for C programs and tcc -P hello.cpp for C++ programs.
I belive this things must work
c:\tc\bin\tcc -c File.c \\ To generate objective file
c:\tc\bin\tcc -o File.obj \\ To generate exe from obj and please use .obj and not .o
c:\tc\bin\ tcc -run File.c \\ to generate exe file without .obj file
c:\tc\bin\File.exe \\ to run the exe file
I dont know why the
tcc -o good.exe File.obj \\not working, the error is good.exe file not found
I think we cant give a name to .exe file in tcc command line prompt.but its possible in gcc. I dont know about TCC much. If i find it i will let you know it !
Just take a look at these http://bellard.org/tcc/tcc-doc.html#SEC3. This is what I found on google . and googling makes you more powerful so keep on googling the things when you dont know .
Thanks
Further to Prof Falken's answer
tcc file.c <-- will compile in C
tcc file.cpp <-- will compile in cpp
tcc file.ext where .ext is anything other than cpp, will compile in C Unless --P is used then cpp is used to compile it, in which case .cpp is used, even if the extension is .c
I am running TCC in a VM and can't copy/paste from there here. But your test should find the same result as mine, if not, then perhaps I erred, but you can test for yourself given this code that works in C and not CPP, and code that works in CPP and not C. You can then experiment with changing the extension, and using -P or not.
The following code works in C only
conly.c
(A C++ expert told me re the following example, works in C and not C++, because C allows void* -> T* conversions. C++ does not)
#include <stdio.h>
#include <stdlib.h>
void main() {int *x=malloc(4);}
The following code works in C++ only
cpponly.cpp
#include <stdio.h>
void main() {
int a=9;
int& b=a;
printf("b=%d",b);
}

Generate assembler code from C file in linux

I would like to know how to generate assembler code from a C program using Unix.
I tried the gcc: gcc -c file.c
I also used firstly cpp and then try as but I'm getting errors.
I'm trying to build an assembler program from 3 different programs
prog1.c prog2.c prog.h
Is it correct to do gcc -S prog1.c prog2.c prog.h?
Seems that is not correct. I don't know if I have to generate the assembler from each of them and then link them
Thanks
According the manual:
`-S'
Stop after the stage of compilation proper; do not assemble. The
output is in the form of an assembler code file for each
non-assembler input file specified.
By default, the assembler file name for a source file is made by
replacing the suffix `.c', `.i', etc., with `.s'.
Input files that don't require compilation are ignored.
so try gcc -S file.c.
From man gcc:
-S Stop after the stage of compilation proper; do not
assemble. The output is an assembler code file for
each non-assembler input file specified.
By default, GCC makes the assembler file name for a
source file by replacing the suffix `.c', `.i',
etc., with `.s'. Use -o to select another name.
GCC ignores any input files that don't require com-
pilation.
If you're using gcc (as it seems) it's gcc -S.
Don't forget to specify the include paths with -I if needed.
gcc -I ../my_includes -S my_file.c
and you'll get my_file.s with the Assembler instructions.
objdump -d also works very nicely, and will give you the assembly listing for the whole binary (exe or shared lib).
This can be a lot clearer than using the compiler generated asm since calls to functions within the same source file can show up not yet resolved to their final locations.
Build your code with -g and you can also add --line and/or --source to the objdump flags.

Resources