Relocating initalization psects in MPLABX with XC8 compiler - pic

I'm developing a bootloader (in C, with a few asm statements thanks to the inline assembly) for a PIC16F876, using MPLABXv5.15 as an IDE and XC8v2.10 as a compiler.
I need the bootloader code to be placed at the end, except for its reset vector, which remains in the 4 first instructions.
In order to prevent the linker from placing code at the beginning, I added the default,-4-FFF option in the ROM ranges field (Project Properties > XC8 Global Options > XC8 Linker > Memory model > ROM ranges) which results in the additional option -mrom=default,-4-FFF and works well so far...
Except for 3 instruction words which are placed in the end_init psect which is itself located at 0x4. By diving into the generated .map file, I located the issue within the generated linking command:
-W-3 --edf=C:\Program Files (x86)\Microchip\xc8\v2.10\pic\dat\en_msgs.txt \
-cs -h+dist/default/production\PJP_BLDR.X.production.sym \
--cmf=dist/default/production\PJP_BLDR.X.production.cmf -z -Q16F76 \
-oC:\Users\ALLART~1\AppData\Local\Temp\sj40.2 --defsym=__MPLAB_BUILD=1 \
-Mdist/default/production/PJP_BLDR.X.production.map -E1 -ver=XC8 \
--acfsm=1493 -ASTACK=0110h-016Fh -pstack=STACK -p_entryTrap_text=FFFh \
-ACODE=00h-03h,01000h-017FFhx2 -ASTRCODE=00h-03h,01000h-01FFFh \
-ASTRING=00h-03h,01000h-010FFhx16 -ACONST=00h-03h,01000h-010FFhx16 \
-AENTRY=00h-03h,01000h-010FFhx16 -ACOMMON=070h-07Fh -ABANK0=020h-06Fh \
-ABANK1=0A0h-0EFh -ABANK2=0110h-016Fh -ABANK3=0190h-01EFh \
-ARAM=020h-06Fh,0A0h-0EFh,0110h-016Fh,0190h-01EFh \
-AABS1=020h-07Fh,0A0h-0EFh,0110h-016Fh,0190h-01EFh -ASFR0=00h-01Fh \
-ASFR1=080h-09Fh -ASFR2=0100h-010Fh -ASFR3=0180h-018Fh \
-preset_vec=00h,intentry=04h,init,end_init -ppowerup=CODE -pcinit=CODE \
-pfunctab=ENTRY -ACONFIG=02007h-02007h -pconfig=CONFIG -DCONFIG=2 \
-AIDLOC=02000h-02003h -pidloc=IDLOC -DIDLOC=2 -DCODE=2 -DSTRCODE=2 \
-DSTRING=2 -DCONST=2 -DENTRY=2 -k dist/default/production\startup.o \
dist/default/production\PJP_BLDR.X.production.o
Where you can find the following argument:
-preset_vec=00h,intentry=04h,init,end_init
Meaning that, according to XC8 manual (here), the ISR, if present, will be placed at 0x4 (as this is the interrupt vector), and the init and end_init psects will be placed right after it (see section 7.2.18 of the manual), no matter the ROM ranges specified before, as it is indicated that psect placed explicitly have priority over ROM ranges (see section 4.8.53 of the manual). So far so good, everything's logical and I only need to find a way to change that! It turns out that there is one! Brilliant!
As stated in XC8 Manual (see section 4.8.6 of the manual which details EXACTLY my issue), I only need to specify -L-pend_init= in the extra linker options (Project Properties > XC8 Global Options > XC8 Linker > Additional options > Extra linker options) (see section 4.9.3.4 of the manual).
And here comes the problem. Whatever I do, nothing changes. The linker command in the .map file stays the same, and this end_init psect stays located at 0x4, no matter what.
The command passed to the linker is the following:
C:\Program Files (x86)\Microchip\xc8\v2.10\bin\xc8-cc.exe" -mcpu=16F76 -Wl,-Map=dist/default/production/PJP_BLDR.X.production.map -DXPRJ_default=default -Wl,--defsym=__MPLAB_BUILD=1 -fno-short-double -fno-short-float -mrom=default,-4-FFF -O0 -fasmfile -maddrqual=ignore -xassembler-with-cpp -I"./inc" -mext=cci -Wa,-a -msummary=+psect,+class,+mem,+hex,-file -L-pend_init=200h -ginhx032 -Wl,--data-init -mkeep-startup -mno-osccal -mno-resetbits -mno-save-resetbits -mdownload -mno-stackcall -std=c99 -gdwarf-3 -mstack=compiled:auto:auto -Wl,--memorysummary,dist/default/production/memoryfile.xml -o dist/default/production/PJP_BLDR.X.production.elf build/default/production/src/main.p1 build/default/production/src/serial.p1 build/default/production/src/nsp.p1 build/default/production/src/rs485slave.p1 build/default/production/src/slip.p1
So it seems that the linker receives this extra command well. However the .map file isn't modified, so I don't understand well how it should proceed. But it's the way to go according to the manual.
You can notice that the extra command passed to the linker is -L-pend_init=200h because out of despair, I just tried a lot of combinations, even placing those arguments in a CODE class, and placing the extra command in the Additional options field in the XC8 Global options, XC8 Linker options and XC8 Compiler options sub-menus. Nothing worked...
I've found this thread, but it doesn't help me (here).
I would have posted a message on Microchip forums, but it's been 3 hours and they haven't approved my registration yet (no offense meant, I simply want to post before stopping today's work ;) )
Thanks to everyone who is going to read until the end !
Thanks by advance and have a nice day !
PS: I know that you may notice that the the command transmitted to the linker specifies -mcpu=16F76 and that I said PIC16F876 (and that 16F76 doesn't allow for boatloader, since it cannot modify it's own flash) but that's the only device I have at home, and I'm only experimenting with placing code wherever I want. I don't think it's related to my problem at all.
PPS: Seems that I cannot say hello, everytime I edit this post to add it at the beginning, nothing happens... Sorry for not saying hello right at the beginning then ;)
Edit 1: It seems it's a bug within xc8 suite (I don't know if it comes from the Hlink linker, or from xc8 driver itself). I tried with xc8v1.45 and it works as expected.

Related

I want to replace 'ld' with 'gcc' in my Makefile to link my kernel objects

In my project I have makefiles which build Solaris kernel modules, and they use gcc to compile files but use ld to link all .o files together into a kernel module. I am trying to include some coverage options like gcov (-fprofile-arcs) or tcov (-xprofile=tcov) in my build, hence I want to replace ld with gcc during linking also.
But as soon as I use replace gcc with ld, the builds start failing with lot of "undefined symbol" errors, even if I use some compile flags and get rid of these errors, the kernel module will not load into my Solaris kernel at all.
For example:
$ /usr/ccs/bin/ld -r -dy -Nstrmod/rpcmod -Nfs/nfs \
-Nmisc/rpcsec -Nmisc/klmmod -Nfs/zfs \
-o debug64/nfssrv \
debug64/nfs_server.o debug64/nfs_srv.o debug64/nfs3_srv.o \
debug64/nfs_acl_srv.o debug64/nfs_auth.o obj64/nfs41_srv.o \
obj64/ctl_ds_srv.o obj64/dserv_server.o
ld works fine but with gcc I get following errors:
/opt/gcc-4.4.4/bin/gcc -m64 -z muldefs \
-Lmod/rpcmod -Lfs/nfs -Lmisc/rpcsec \
-Lmisc/klmmod -Lfs/zfs \
-o obj64/nfssrv \
obj64/nfs_server.o obj64/nfs_srv.o obj64/nfs3_srv.o
obj64/nfs_acl_srv.o obj64/nfs_auth.o obj64/nfs41_srv.o
obj64/ctl_ds_srv.o obj64/dserv_server.o
Undefined first referenced
symbol in file
hz obj64/nfs_server.o
p0 obj64/nfs_server.o
nfs_range_set obj64/nfs41_srv.o
getf obj64/nfs_server.o
log2 obj64/nfs4_state.o
main /usr/lib/amd64/crt1.o
stoi obj64/ctl_ds_srv.o
dmu_object_alloc obj64/dserv_server.o
nvpair_name obj64/nfs4_srv.o
__dtrace_probe_nfss41__i__destroy_encap_session obj64/nfs41_srv.o
__dtrace_probe_nfssrv__i__dscp_freeing_device_entries obj64/ctl_ds_srv.o
mod_install obj64/nfs_server.o
xdr_faststatfs obj64/nfs_server.o
xdr_WRITE3res obj64/nfs_server.o
svc_pool_control obj64/nfs_server.o
Warning the option -L allows to specify a path where to search for libraries, to specify a library you want to link with you (also) have to use the option -l
So a priori you have to add the options -lrpcmod -lnfs -lrpcsec -lklmmod -lzfs
More details in GCC Linking Options
By default, the GNU linker called through the gcc compiler driver will try to create a standard executable. Consequently, if you don't tell it otherwise, ld will use its default linker script, the C startup code and it will look for a main() routine and everything else that makes a valid executable.
I'm not too familiar with Solaris, but would bet this will not be suitable to build kernel modules. I would expect kernel modules will at least require some options like -ffreestanding, -nostdlibs and most likely a non-default linker script that's probably very different from the default one used for applications.
Even if you manage to link your kernel modules this way, I seriously doubt you will be finished. The gcov instrumentation routines most likely do not expect to live within a kernel driver but expect a proper C execution environment (e.g. it will at least expect to fopen() a file to fwrite() its findings). A kernel driver, however, does not have this comfort. You'll probably find yourself confronted with the problem to get the gcov data somehow out of your kernel modules.
Not saying this is not doable, but it certainly will be a lot of work.

Is there a method to make `gcc' dump/display all the flags in use while compiling code?

Do note this is different from
Get the compiler options from a compiled executable? which I did go through in detail.
Although -frecord-gcc-switches is great, it only captures the command line arguments.
For example, I am not interested in capturing -O2 which is usually passed in command line. I am more curious about recording all the flags like -fauto-inc-dec which are enabled by -O2.
(In contrast to the link above, do note that I have access to the source, the compiler and the build infrastructure. I just want to capture the flags during compilation. Not picky about any specific gcc version)
You can try -fverbose-asm. That dumps the optimisation options used in a comment at the top of the assembly file.

Running GCC preprocessor -fdirectives-only *without* implicit -dD

Basically, I want to do what the title says.
I have some mildly complex header files, and I want to generate a single header file I can release as the public interface of a DLL.
I'm generating the header file as follows:
${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} -fdirectives-only -P \
-E ${CMAKE_CURRENT_SOURCE_DIR}/dll_header_base.h -o generated_public_header.h
If I run the compiler without -fdirectives-only, the precompiler is much more aggressive about stripping out contents of the header. The output of -fdirectives-only is almost what I want, but that particular flag forces the -dD flag on as well, which prepends all the compiler-defined macros to the generated header (450 lines of them!).
I don't really understand why -fdirectives-only forces -dD in the first place, and for my case, the later flag basically makes it useless. Looking at the options for -dLETTER, there also seems to be no way to turn it off.
How do I extract the directives-only preprocessed output without all the additional cruft?
Yes, I could pretty easily solve this with command line tools, but I want to keep the solution entirely constrained to the compiler/CMAKE. Eventually, I'd like to also support building on windows.

What do the -f and -m in gcc/clang compiler options stand for

Summary: What do the -f and -m in gcc and clang compiler options stand for?
Details:
When using clang I've noticed that many compiler options start with -f and others start with -m. I assume that there is some historical reason for this and I was curious so I looked at the gcc help and saw the following:
Options starting with -g, -f, -m, -O, -W, or --param are automatically
passed on to the various sub-processes invoked by gcc. In order to
pass other options on to these processes the -W options must
be used.
If I had to guess I think that -f might stand for frontend and -m for machine. But I'd be interested to hear a more comprehensive answer, possibly including the other sub-processes that gcc invokes.
I don't have specific sources that state what 'f' and 'm' mean, but we can infer based on usage patterns found in documentation.
'f' stands for 'flag'.
Flags are on if specified via '-fFLAG' and off via '-fno-FLAG'
ex:
-fpic # flag to set position independent code
-fno-builtin # don't recognize build in functions ...
The technical definition is that 'f' defines "Control the interface conventions used in code generation".
Src:
https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html
(e.g -fpci, when this flag is set)
'm' stands for mode. One general characteristic is that it sometimes has parameters. e.g
-mabi=name #abi mode = name
-mcpu=cpu
Src:
https://gcc.gnu.org/onlinedocs/gccint/Standard-Names.html (e.g ... when this mode...)
According to gcc onlinedocs, options of the form -ffoo and -fno-foo stand for machine independent code generation conventions.
Examples: fpic, -fno-pic
-m options stand for machine dependent options.
eg: -mcpu, -march, -matomic
https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#Code-Gen-Options or https://home.cs.colorado.edu/~main/cs1300/doc/gnu/gcc_2.html#SEC43
https://gcc.gnu.org/onlinedocs/gcc/Submodel-Options.html#Submodel-Options or https://home.cs.colorado.edu/~main/cs1300/doc/gnu/gcc_2.html#SEC16

How do I strip local symbols from linux kernel module without breaking it?

If I do --strip-debug or --strip-unneeded, I have the .ko that lists all function names with nm, if I do just strip foo.ko I have a kernel module that refuses to load.
Does anyone know a quick shortcut how to remove all symbols that are not needed for module loading so that people cannot reverse engineer the API:s as easily?
PS: For all you open source bigots missionaries; this is something that general public will never be using in any case so no need to turn the question into a GPL flame war.
With no answer to my previous questions, here are some guesses that could also be some clues, and a step to an answer:
From what I recall, a .ko is nothing but an .o file resulting from the merge of all the .o files generated by your source module, and the addition of a .modinfo section.
At the end of any .ko building Makefile, there is an LD call: from what I recall, ld is called with the -r option, and this is what create that .o file that the Makefile calls a .ko. This resulting file is not to be confused with an archive or object library (.a file), that is just a format archiving / packaging multiple .o files as one: A merged object is the result of a link that produces yet another .o module: But in the resulting module, all sections that could be merged have been, and all public / external pairs that could be resolved have been inside those sections.
So I assume that you end up with your .ko file containing all your "local" extern definitions:
Those that are extern because they
are used to call across the .o
modules in your .ko (but are not
needed anymore since they are not
supposed to be called from outside
the .ko), and
those that the .ko module DO need to
properly communicate with the loader
and kernel.
The former have most likely already been resolved by ld during the merge, but ld has no way to know whether you intend to have them also callable from outside the .ko.
So the extraneous symbols you see are those that are extern for each of your .o files, but are not needed as extern for the resulting .ko.
And what you are looking for is a way to strip only those.
Does this last paragraph properly describe the symbols you want to get rid of?
I think this is exactly what we are
talking about here.
OK, then it looks like one solution is to "manually" remove the extraneous symbols. The "strip" utility seems to allow individually stripping (or keeping) of symbols, so you would have to use one --strip-all and a small bunch of --keep-symbol= . Note that --wildcard might help a bit, too. You can do the opposite, of course, keep all and individually strip, depending on what's the most convenient.
A good start could be to remove all the symbols that you explicitly defined in your module for cross-module linking and don't want to appear - just leaving the obvious useful ones, things like init and exit. And to not touch those that have been generated by / belong to the kernel dev software infrastructure. Then trial and error until you find the right recipe... In fact, I would think that about all your own symbols might be removable, apart from those you explicitly defined yourself as EXPORT_SYMBOL (and init / exit, of course).
Good luck! :)
PS:
In fact, it seems that the required source information exists in all .ko projects to perform the required stripping automatically: Unless I'm missing something, it seems that anything that's not EXPORT_SYMBOL or explicitly inserted by the build software could theoretically be stripped by default at the end of "ld -r" time that ends a .ko build. It's just that I don't think the toolchain (compiler / linker) have provision / directives / options to individually designate "strip or keep" syms for the relocatable link / merge. Otherwise, some modifications in the EXPORT_SYMBOL macro and in a few other places could probably achieve the result you're after, and shave some bytes from most .ko files in any Linux system.
I just built a kernel without realizing the kernel config had debug symbols enabled, so the size of the resulting modules were quite large. This worked for me:
# du -sh /lib/modules/3.1.0/
1.9G /lib/modules/3.1.0/
# find /lib/modules/3.1.0/ -iname "*.ko" -exec strip --strip-debug {} \;
# du -sh /lib/modules/3.1.0/
134M /lib/modules/3.1.0/
Find all files in /lib/modules/3.1.0 named *.ko and execute strip --strip-debug on each of them.
I'm not sure I understand what the problem really is:
When developing a .ko, if I don't explicitly add something like
ccflags-y += -ggdb -O0 -Wall
into my Makefile, I don't get any symbol but for those that I publish or external ref myself. I'm sure I don't get any other symbols for several good reasons:
the resulting .ko file is considerably smaller,
dumping the file and analyzing the ELF shows the tables are not there,
I can't see nor access the symbols in kgdb.
So I'm a little puzzled at your question, actually?... What are those symbols you do see in your .ko (and don't want to)?
How are they declared in your source file?
In which ELF sections do they end up?
And (sorry, dumb question ahead): Did you define static all things that didn't need to be seen outside of their own module?
In addition to filofel's post:
The reason stripping userspace shared libraries keeps them functioning is because their exported symbols are in the .dynsym section which is never stripped. .ko files however do not use dynsym.
people have reported success with
strip --strip-unneeded
strip -g XXX.
My Previous problem like what you happened is sloved by this command in embedded device with Linux Kernel 3.0.8.

Resources