Thursday, April 09, 2009

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.

$ 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

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.

$ 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

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.

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, "")


Tuesday, March 17, 2009

Better build system

I was using “make”(http://en.wikipedia.org/wiki/GNU_build_system) to build and clean my projects. The makefiles grew bigger enough to not maintainable state. Recently I came to know about waf(http://code.google.com/p/waf/) from a forum, so decided to give a try. I went through the waf documentation and it took 2 hours to understand how it works and it took 2 days to convert all my makefiles to waf wscripts and wscript_build files.

The basic problem with make was I have write rules to how to build object files from source and

then to clean I have to write how to delete the object files. With waf the problem is simplified, you have to tell what all source files and it will take care of how to compile and link. It will also take care of how to clean the project and the dependency between files are also taken care, so no need for gcc –M and dependency files etc. The feature I liked in waf is it has colored output with progress bar :)

The other problem solved in Ace project compilation was build configuration. Waf will configure the project for the first time, so it solved the different cross compiler required for Ace OS.

Waf(http://code.google.com/p/waf/) is really good alternative/replacement for make tools.

Tuesday, December 16, 2008

Putty Tips

Putty title
I wanted to change putty title to reflect current working directory of the remote machine to distinguish multiple putty windows easily.

PUTTY_TITLE=`hostname`:`tty | cut -f 4 -d "/"`
export PS1='$PWD>^[]2;$PWD:$PUTTY_TITLE^G'

To insert in vi editor the "^[" character in insert mode press control-V and then the Escape key. ^G is created by pressing control-G.


Passwordless connection to HPUX machines
Since I was forgetting my passwords for HPUX machines, I decided to try SSH public/private key authentication to get rid of passwords. After some struggle I managed to login in to HPUX machines using Putty without entering a password.

Before I forget all those steps which are not part of my daily job, I wanted to log them and so here it is.
  1. Login to HPUX machine using your login and password
  2. Create a .ssh directory under your home directory mkdir .ssh
  3. Create public/private key pair ssh-keygen –t rsa
  4. Add the public key to authorized_keys2 file cat id_rsa.pub>> authorized_keys2
  5. Now ftp the private key file(id_rsa) to your Windows machine.
  6. Covert the private key file format to putty private key file format. (Use puttygen.exe and then load and save the private key file).
  7. Now in putty, select the host and select SSH as protocol and in SSH options on the left hand tab select Auth and select the private key file.
If you get “server refused our key” error then I would suggest running sshd with debug option. (/usr/sbin/sshd -d -d -d &)

You can also check the permission of your files and folders.
  • chmod 600 authorized_keys2
  • chmod 700 .ssh
  • Also check your home directory permission.
It should work. If it is not, you can try running the ssh client in debug mode from the same server. (ssh -l username servername -v -v -v)

Passwordless connection to Tru64 machines
It is almost same as HPUX configuration but the directory name should be ".ssh2" instead of ".ssh". And it should contain a text file named "authorization"; the contents of that file should be list of public key files separated by newline.
Example:
/home/samuel/.ssh2>ls
authorization id_rsa_2048_a id_rsa_2048_a.pub random_seed
/home/samuel/.ssh2>cat authorization
Key id_rsa_2048_a.pub
Someother tools I came to know when I was searching Putty enchancements
  1. I wanted some small utility to avoid digging through Start menu Programsto find Putty or any other program to launch it. I want a small command line kind of utility and found Launchy it can launch any program by typing few letters of that program.
  2. Sometime I start source control/compilation of kernel from my office and want to continue things from my home. But since terminal emulators such as Putty are bound to local machine, I used to open new terminal session or use remote desktop connection to my office machine to continue my work. One of my colleagues told me about GNU screen and how it can solve the problem. Here is some good introduction to screen.
Putty sessions
I was searching for method to launch Putty session quickly and saw the following article Multiple putty addons http://www.thegeekstuff.com/2008/08/turbocharge-putty-with-12-powerful-add-ons-software-for-geeks-3/

Previously I was using "Putty Session Manager" to categorize and lanuch putty sessions.

Enabling colors in vim in putty terminal

Saturday, November 22, 2008

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 much bigger 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.
    Non-Debug Version:  81.2K Code, 17.0K Data,  98.2K Total
    Debug Version:     155.8K Code, 49.1K Data, 204.9K Total

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.

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

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.

gcc compiler took the following time to compile Ace source code.
real    0m51.125s
user    0m36.975s
sys     0m11.185s

icc compiler took the following time to compile Ace source code.
real    1m44.366s
user    0m59.107s
sys     0m20.946s

Gcc produced double the size of kernel.sys produced by icc. (I used GNU linker(ld) and ar).

gcc output size:
[samuel@linux Ace3]$ 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

icc output:
[samuel@linux Ace3]$ 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

So it is easy to use icc instead of gcc. However since I am using Windows and icc is free only for Linux for non commerical purposes. I stick to gcc to compile Ace in Windows. 

Thursday, November 06, 2008

GNU make slow build process

While building one my project it was taking too much time; the project was taking around 40-60 seconds to build and around 20 seconds to clean. I was frustrated with this because the debugging cycle time for my project was going high.

So I decided to stop debugging my project and start debugging the build process. In my makefile I had .SILENT option and I removed it to see what is going.  The following was the output
make[1]: Entering directory `/cygdrive/g/Projects/Ace3/src/lib'
make[2]: Entering directory `/cygdrive/g/Projects/Ace3/src/lib/string'
make[2]: Nothing to be done for `all'.
..
make[1]: Leaving directory `/cygdrive/g/Projects/Ace3/src/lib'
make[1]: Entering directory `/cygdrive/g/Projects/Ace3/src/kernel'
..
make[2]: Leaving directory `/cygdrive/g/Projects/Ace3/src/kernel/pic'
New kernel is at /cygdrive/g/Projects/Ace3/obj/kernel.sys
/cygdrive/g/Projects/Ace3/img/create_bootcd.sh
Everything was fast, however there was huge delay before getting the output “make[1]: Leaving directory `/cygdrive/g/Projects/Ace3/src/lib'”

Then I tried invoking make with –d (debug) option and it gave the following output
This program built for i686-pc-cygwin
Reading makefiles...
Reading makefile `makefile'...
Reading makefile `/cygdrive/g/Projects/Ace3/make.conf' (search path) (no ~ expansion)...
Reading makefile `boot_module.d' (search path) (don't care) (no ~ expansion)...
Reading makefile `interrupt.d' (search path) (don't care) (no ~ expansion)...
Reading makefile `ktrace.d' (search path) (don't care) (no ~ expansion)...
Reading makefile `main.d' (search path) (don't care) (no ~ expansion)...
And it took lot of time before continuing the from the above step, so I knew something wrong with the main.c dependency file, so I opened it and it had too many entries. I casually checked the size of the file and it was 50MB. That explained why make was slow. I carefully examined the dependency entries and found they were repeating. I opened make.conf and checked the rule for making dependency file and found the culprit 
%.d:    %.c
@$(CC) -c -M $< -I$(INCLUDE) $(CFLAGS) >> $@
The output redirection symbol >> caused the problem. It appended the dependency rules every time I compiled and increased the size of .d file.  I replaced >> with > and now incremental build process completes in 3 seconds.