Search This Blog

Showing posts with label make. Show all posts
Showing posts with label make. Show all posts

Friday, August 28, 2009

Debugging gcc behavior

While compiling a FreeBSD kernel I encountered the following error message from GNU assembler
Error: suffix or operands invalid for `mov'

I was not sure whether the error is because of my changes are not. But still I have to debug the problem and solve it, so I decided to find what is wrong with the mov instruction. But since gcc created a temporary file and invoked as to assemble it, I couldn’t find the temp file anymore.
Googled and find the following gcc options to find what gcc does.
gcc –v is verbose mode, which prints all the action/scripts gcc is doing.
gcc -### similar to –v but wont execute any commands.
gcc –save-temps saves all the temporary files generated by the gcc. Useful if you want to see the assembly output passed to gnu assembler.
gcc –E Just preprocess the c file
gcc –S generate assembly file.
With gcc –v –save-temps, I got the temporary assembler file used by assembler. Since reading machine generated assembly file is difficult, I tried to find the C source code corresponding to the error. From nearest .file assembler directive I found the C file name and from the .loc directive I found the line number. And the following was the inline assembly in the C file.
__asm __volatile("movl %%ss,%0" : "=rm" (sel));

Was surprised what is wrong with this and why my assembler giving error. Googled again and found this link - http://kerneltrap.org/node/5785. It seems newer gnu assembler(>=2.16) wont support long read/write operations(mov) on segment registers(ds,ss...). So changed the above source to movw %%ss, %o and it compiled perfectly. :)

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.