Archive for the ‘C’ Category
Unreferenced symbols – EXPORT_SYMBOL
I wrote ACPI driver for Ace and try to load it into kernel. It was failing with the error message symbol not found.
The log file content says AcpiGetName was not found.
[shell]
$ cat log.txt
Driver for id acpi : acpi.sys
../src/kernel/pm/elf.c:343:FindElfSymbolByName(): Symbol not found AcpiGetName(c01a2148:1869) string table c01aa619
[shell]
After exploring the Acpi-CA source code and Ace kernel code, I couldn’t figure out why the symbol is missing. Then I tried to dump the symbol table for Acpi library and kernel.sys.
[shell]
$ nm build/default/src/kernel/libacpi.a | grep GetName
U AcpiExGetNameString
000001e3 T AcpiExGetNameString
000001b7 T AcpiPsGetName
000000f4 T AcpiGetName
$ nm build/default/src/kernel/kernel.sys | grep GetName
c0135163 T AcpiExGetNameString
c0137bfb T AcpiPsGetName
[/shell]
It is obvious during kernel link process some how the linker is losing AcpiGetName. Within few seconds I realized that the linker is doing optimization on the output to remove unreferenced sections. So I googled for how to avoid this and found –no-gc-sections is the ld option to do it. However even after giving this option to linker to was removing the unreferenced symbols; I kept on trying to find a solution for making the linker to include unreferenced symbols in the output… I didn’t find the solution.
Then I started thinking how linux kernel is avoiding this problem and I it flashed seeing EXPORT_SYMBOL kind of macro in some source. So I googled for it and got the answer – use the symbol in storage, so that it will be referenced, so that linker will include it in the output.
[c]
struct kernel_symbol
{
unsigned long symbol;
char * name;
};
#ifndef MODULE_SYMBOL_PREFIX
#define MODULE_SYMBOL_PREFIX “”
#endif
#define __EXPORT_SYMBOL(sym, sec) \
static const char __kstrtab_##sym[] \
__attribute__((section(“__ksymtab_strings”))) \
= MODULE_SYMBOL_PREFIX#sym; \
static const struct kernel_symbol __ksymtab_##sym \
__attribute__((section(“__ksymtab” sec), unused)) \
= { (unsigned long)&sym, __kstrtab_##sym }
#define EXPORT_SYMBOL(sym) \
__EXPORT_SYMBOL(sym, “”)
[/c]
Porting to “Intel C Compiler”
In this post, I will explain how to easy it is to compile/port C programs and makefiles designed for GCC(GNU compiler collection) can be used with ICC(Intel C Compiler)
The necessity for using ICC happened to me because gcc was generating too big object files. Ace is using ACPI-CA(http://acpica.org/) as it is ACPI driver. After compilation the ACPI library is around 7M in debug version and around 500K in non-debug version. But from http://acpica.org/download/changes.txt it seems Microsoft C compiler produce smaller code.
[shell]
Non-Debug Version: 81.2K Code, 17.0K Data, 98.2K Total
Debug Version: 155.8K Code, 49.1K Data, 204.9K Total
[/shell]
So I decided to try “Intel Compiler” as replacement for GCC. Things were easy, since icc has options which is similar to gcc.
You can get the details of portability options from icc documentation – http://www.intel.com/software/products/compilers/docs/clin/main_cls/index.htm.
I just changed my make.conf file to check the compiler in use and use appropriate options. I removed -fno-leading-underscore and –Wall. I removed –Wall because it was giving lot of warnings, we have to fix our code sometime soon. I removed -fno-leading-underscore because there is no equivalent option in icc, however icc does not adds underscores to symbols anyway.
I added –O1
option because the kernel was panicked during boot with invalid opcode exception, I believe it was because of some MMX register usage by icc. So I settled with –O1 now.
[shell]
ifeq ($(CC),gcc)
DEBUG_FLAGS= -gdwarf-2 -g3
CFLAGS+= -Wall -Wno-multichar $(DEFINES) -nostartfiles -ffreestanding -funsigned-char -fno-leading-underscore -c -fno-stack-protector $(DEBUG_FLAGS) $(CUSTOM_FLAG)
else
DEBUG_FLAGS= -gdwarf-2 -g
CFLAGS+= -O1 -Wno-multichar $(DEFINES) -nostartfiles -ffreestanding -funsigned-char -c -fno-stack-protector $(DEBUG_FLAGS) $(CUSTOM_FLAG)
endif
[/shell]
I also made some static variables in kernel/i386/gdb_stub.c to non-static because icc appends .0 to static variables but it forgets the same name when referenced in a inline assembly code in the same file. After removing the static attribute it is working fine.
Compilation time:
gcc compiler took the following time to compile Ace source code.
[shell]
real 0m51.125s
user 0m36.975s
sys 0m11.185s
[/shell]
icc compiler took the following time to compile Ace source code.
[shell]
real 1m44.366s
user 0m59.107s
sys 0m20.946s
[/shell]
Size:
Gcc produced double the size of kernel.sys produced by icc. (I used GNU linker(ld) and ar).
gcc output size:
[c]
$ ls -lh /home/samuel/Projects/Ace3/obj/
-rw-rw-r– 1 samuel samuel 372K 2008-11-22 18:17 acpi.a
-rw-rw-r– 1 samuel samuel 545K 2008-11-22 18:17 arch.a
-rwxrwxr-x 1 samuel samuel 1.3M 2008-11-22 18:17 kernel.sys
-rw-rw-r– 1 samuel samuel 62K 2008-11-22 18:17 libds.a
-rw-rw-r– 1 samuel samuel 40K 2008-11-22 18:17 libheap.a
-rw-rw-r– 1 samuel samuel 39K 2008-11-22 18:17 libstring.a
-rw-rw-r– 1 samuel samuel 9.5K 2008-11-22 18:17 libsync.a
-rw-rw-r– 1 samuel samuel 91K 2008-11-22 18:17 pic.a
-rw-rw-r– 1 samuel samuel 23K 2008-11-22 18:17 pit.a
-rw-rw-r– 1 samuel samuel 21K 2008-11-22 18:17 rtc.a
[/c]
icc output:
[c]
$ ls -lh /home/samuel/Projects/Ace3/obj/
-rw-rw-r– 1 samuel samuel 352K 2008-11-22 16:25 acpi.a
-rw-rw-r– 1 samuel samuel 230K 2008-11-22 16:24 arch.a
-rwxrwxr-x 1 samuel samuel 528K 2008-11-22 16:25 kernel.sys
-rw-rw-r– 1 samuel samuel 38K 2008-11-22 16:23 libds.a
-rw-rw-r– 1 samuel samuel 22K 2008-11-22 16:23 libheap.a
-rw-rw-r– 1 samuel samuel 21K 2008-11-22 16:23 libstring.a
-rw-rw-r– 1 samuel samuel 11K 2008-11-22 16:23 libsync.a
-rw-rw-r– 1 samuel samuel 19K 2008-11-22 16:24 pic.a
-rw-rw-r– 1 samuel samuel 8.4K 2008-11-22 16:24 pit.a
-rw-rw-r– 1 samuel samuel 13K 2008-11-22 16:24 rtc.a
[/c]
Conclusion: So it is easy to switch to icc instead of gcc.
CodeLite – IDE for C
For my C projects I was using Notepad++ as my editor/IDE for some time. Although notepad++ is good, it is lacking the integration with a code browser, source control and debugger. I came to know about a new IDE – CodeLitewhen I was searching for ctags for windows. It has integrated support for Subversion, ctags, gdb.
Since it is advertised to have multi-platform GUI, I was little reluctant to install and try(I have tried lot of multi-platform GUI applications and never satisfied with the look and feel of them). But wxWidgets makes the CodeLite to look like native windows application. CodeLite has lot of features and it looks very similar to Microsoft VC++ IDE.
Code browsing is very easy with CodeLite. It is has a very light explorer and also workspace view through which you can browse your project “easily”. You can switch between header and c file “easily” using the “Swap Header/implementation file” in the context menu. Context menus “Goto declaration” and “Goto Implementation” are handy to browse through code quickly.
If you are using cygwin and custom makefile – you can use a script as custom build command – see Notepad++ as IDE post for more details.
I use the following command to build(because I use gcc cross compiler)
[shell]c:\cygwin\bin\bash -l -c ‘cd $ACE_ROOT/src;PATH=/usr/cross/i586-elf/bin/:$PATH:;make 2> err; sed -e “s@\(\/cygdrive\/\)\([a-zA-Z]\)@\2:@g” err; rm err’. [/shell]
And the following command to clean
[shell]c:\cygwin\bin\bash -l -c ‘cd $ACE_ROOT/src;PATH=/usr/cross/i586-elf/bin/:$PATH:;make clean’[/shell]
Codelite supports debugging through gdb; embedded and remote targets also supported. Since I am using a emulator to test my kernel, I have to use remote debugging in GDB to test my OS. Codelite integrates well with GDB remote debugging. I use the following GDB commands as startup gdb commands.
[shell]
set print pretty on
directory src/kernel
symbol obj/kernel.sys
source img/gdb/general.gdb
source img/gdb/stack.gdb
source img/gdb/vm.gdb
[/shell]
If SVN is configured, using codelite you can see difference between two versions of a same file.
By default codelite uses the default diff viewer.
It can be changed from Plugins menu -> Subversion->Options and setting the value appropriately.
I use WinMerge to see difference of source files and have the following settings:
External Diff viewer: C:\Program Files\WinMerge\WinMergeU.exe
Arguments : /dl %bname /dr %mname %base %mine
Another good thing about CodeLite is it is under development and your bug report/feature requests are solved within short time frame.
You can download CodeLite from www.codelite.org. It has installer for Windows and Linux also.
Source code browsing tool
In UNIX environment there is the famous “cscope”, to browse the source code and make changes. Using cscope it is easy to browse/edit the source code, cross reference all the functions calling a function, including a file etc.
In windows, I was using notepad++’s find files options browse C source code. Today I decided to find an open source full fledged source navigator for windows.
I started with notepad++ plugin – “Function List”. But it is just not enough for a project source browsing. Google searches gave me cscope port of windows(http://cscope.sourceforge.net/). However I wanted more – the GUI. With few more searches I found Source Navigator – http://sourcenav.sourceforge.net/
Soucrce Navigator is very useful, I just added my project and it give me full list of symbols. Editing a function is just clicking it. Since I am using notepad++ for editing anything, I changed the editor preference to notepad++. To do go to Source Navigator->File menu->Project Preference->Edit-> External editor and give the following line
“C:\Program Files\Notepad++\notepad++.exe” -n%l
Now I can easily browse the source code in Source Navigator and edit it in Notepad++ with few keystrokes.
Bitfield inside a Union
When coding Ace physical memory manager, I came to a situation where I have to use lot of bit operations on a integer variable. The code looked little ugly because of the explicit bit operations(left shift
[c]
typedef struct struct_x
{
union
{
int all;
int x:1,y:1,z:30,
};
};
[/c]
The above code wasn’t working; debugging further I found that the values for bitfields are not calculated correctly.
After some digging I found that, the bitfield hint is ignored by the compiler since it is directly under union. So the compiler treated the fields x,y,z as separate integer instead of considering as one.
I modified the code to pack the bitfields inside a structure and it worked correctly.
[c]
typedef struct struct_x
{
union
{
int all;
struct
{
int x:1, y:1, z:30,
}_;
};
};
[/c]
And yes, just an underscore(_) is a valid identifier.
Leading underscores in C
C compilers were prepending an underscore to all the symbols (function, variable names). I read from somewhere this is to avoid name collision with other language libraries. This convention was started with UNIX. When UNIX was written in C to use the existing assembly libraries, C symbols were added with a leading underscore by compilers and linkers.
Currently there is no need for this unless otherwise if you want to use old library. So most of the new C compilers are not adding leading underscores; however it also depends on the platform and object file. For example, Linux a.out GCC does such prepending, while Linux ELF GCC does not.
To explicitly tell the GCC compiler to not to use leading underscore you can use –fno-leading-underscore option.
Note: FORTRAN was adding both leading and trailing underscores to avoid name collision to avoid naming collision with C.