Linux

Tuesday, May 31, 2005

Structure packing in gcc

This is a quite common problem.It took some time for me to find out the solution.
gcc does not support the #pragma directives.

The __attribute__((packed)) of gcc helps you to do structure packing.It has to be added to the definition of each and every structure to be packed.

E.g:Here is a packed structure in which the field b is packed, so that it immediately follows a
struct data
{
char a;
int b;
}__attribute__((packed));

The attribute can be applied to the individual fields of a structure than applying it to entire structure as in this example

struct foo
{
char a;
int x[2] __attribute__ ((packed));
};


Related gcc warnings:
-Wpacked Warn if a structure is given the packed attribute, but the packed attribute has no effect on the layout or size of the structure. Such structures may be misalignedfor little benefit. For instance, in this code, the variable f.x in structbar will be misaligned even though struct bar does not itself have the packed attribute:
struct foo

{
int x;
char a, b, c, d;
} __attribute__((packed));
struct bar
{
char z;
struct foo f;
};

-Wpadded Warn if padding is included in a structure, either to align an element of the structure or to align the whole structure. Sometimes when this happens it is possible to rearrange the fields of the structure to reduce the padding and so make the structure smaller.

Just now came across another option in gcc

-fpack-struct

Packs all structure members together without holes.
Warning: the ‘-fpack-struct’ switch causes GCC to generate code that isnot binary compatible with code generated without that switch.


-Excerpts from the gcc3.3.2 documentation


Monday, May 30, 2005

Compiling a kernel module

Kernel modules need to be compiled with certain gcc options to make them work. In addition, they also need to be compiled with certain symbols defined. This is because the kernel header files need to behave differently, depending on whether we're compiling a kernel module or an executable. You can define symbols using gcc's -D option, or with the #define preprocessor command.

-c: A kernel module is not an independant executable, but an object file which will be linked into the kernel during runtime using insmod. As a result, modules should be compiled with the -c flag.
-O2: The kernel makes extensive use of inline functions, so modules must be compiled with the optimization flag turned on. Without optimization, some of the assembler macros calls will be mistaken by the compiler for function calls. This will cause loading the module to fail, since insmod won't find those functions in the kernel.
-W -Wall: A programming mistake can take take your system down. You should always turn on compiler warnings, and this applies to all your compiling endeavors, not just module compilation.
-isystem /lib/modules/`uname -r`/build/include: You must use the kernel headers of the kernel you're compiling against. Using the default /usr/include/linux won't work.
-D__KERNEL__: Defining this symbol tells the header files that the code will be run in kernel mode, not as a user process.
-DMODULE: This symbol tells the header files to give the appropriate definitions for a kernel module.

We use gcc's -isystem option instead of -I because it tells gcc to surpress some "unused variable" warnings that -W -Wall causes when you include module.h. By using -isystem under gcc-3.0, the kernel header files are treated specially, and the warnings are surpressed.
Sample:
gcc -D__KERNEL__ -DMODULE -I/lib/modules/`uname -r`/build/include -O2 -c testmod.c

This is much simpler in 2.6 kernel refer [2]
for USB drivers if the module needs to be loaded as and when the device is plugged in use

-DCONFIG_HOTPLUG

To solve the problem of unresolved symbols in kernel module


Add the following at the starting to the kernel module source file you are creating.

#if defined __KERNEL__

#include <linux/config.h>

#if defined( CONFIG_MODVERSIONS ) && ! defined( MODVERSIONS )

#define MODVERSIONS

#endif

/* modversions.h should be before should be before module.h */

#if defined( MODVERSIONS )

#include <linux/modversions.h >

#endif

#include "linux/module.h"

#include "linux/version.h"

/* Now your module include files & source code follows */


Related Links:
[1] http://www.tldp.org/LDP/lkmpg/2.4/html/x208.html
[2] http://www.tldp.org/LDP/lkmpg/2.6/html/x181.html

Thursday, May 26, 2005

USB Device Filesystem basics

The USB device filesystem is a dynamically generated filesystem, similar to the /proc filesystem. This filesystem can be mounted just about anywhere, however it is customarily mounted on /proc/bus/usb, which is an entry node created by the USB code, intended to be used as a mount point for this system. Mounting in other locations may break user space utilities, but should not affect the kernel support.

You need to select "Preliminary USB Device Filesystem" to make this work. You also need to enable general /proc support, and to have it mounted (normally automatic).

To mount the filesystem, you need to be root. Use the mount command:
mount -t usbdevfs none /proc/bus/usb

Note that the none keyword is arbitrary - you can use anything, and some people prefer to use usbdevfs, as it makes the mount output look better.

If you do not want to have to mount the filesystem each time you reboot the system, you can add the following to /etc/fstab after the /proc entry:
none /proc/bus/usb usbdevfs defaults 0 0.
This has the same effect as the mount command.
After you have mounted the filesystem, the contents of /proc/bus/usb should look something like:
dr-xr-xr-x 1 root root 0 Jan 26 10:40 001
-r--r--r-- 1 root root 0 Jan 26 10:40 devices
-r--r--r-- 1 root root 0 Jan 26 10:40 drivers

Linux Dynamic Linking

Linux allows dynamic linking of libraries during the time the executable is loaded or when required (shared libraries are usually of .so.x.y.z)

The shared object can be created using the steps mentioned in [3].
Suppose the shared library is named libmylib.so
If you create an executable using the shared object while compilation of the executable
gcc source.c –lmylib –o myapp


In this case when myapp is loaded/started the shared object mylib is loaded.This is the very basic method of using a shared library.

There is a way to load/unload the dl libraries as needed using the dlopen,dlclose routines
Use –ldl while linking and include dlfcn.h in the executable

The related functions are

dlopen()

The dlopen function opens a library and prepares it for use.

void * dlopen(const char *filename, int flag);

If filename an absolute path, dlopen() will just try to use it .Otherwise, dlopen() will search for the library in the following order:

*List of directories in the user's LD_LIBRARY_PATH environment variable.

*The list of libraries specified in /etc/ld.so.cache (which is generated from /etc/ld.so.conf).
/lib, followed by /usr/lib

Note the order here; this is the reverse of the order used by the old a.out
loader. The old a.out loader, when loading a program, first searched /usr/lib, then /lib .This shouldn't normally matter, since a library should only be in one or the otherdirectory (never both)

the value of flag must be either
RTLD_LAZY, meaning ``resolve undefined symbols as code
from the dynamic library is executed'', or
RTLD_NOW, meaning ``resolve all undefined symbols before dlopen() returns and fail if this cannot be done''.
RTLD_GLOBAL may be optionally or'ed with either value inflag, meaning that the external symbols defined in the library will be made available to subsequently loaded libraries

If the libraries depend on each other (e.g., X depends on Y), then you need to load the dependees first (in this example, load Y first, and then X).

dlerror()

Errors can be reported by calling dlerror(), which returns a string describing the error from the last call todlopen(), dlsym(), or dlclose(). One oddity is that after calling dlerror(), future calls to dlerror() will return NULL until another error has been encountered.

dlsym()
dlsym() looks up the value of a symbol in a given (opened) library.

void * dlsym(void *handle, char *symbol);
the handle is the value returned from dlopen, and symbol is a NULL-terminated string.

dlclose()

The converse of dlopen() is dlclose(), which closes a DL library. The dl library maintains link counts for dynamic file handles, so a dynamic library is not actually deallocated until dlclose has been called on it as many times as dlopen has succeeded on it.

This is an example i came across from which i learnt how to use the above functions


#include "stdio.h"
#include "stdlib.h"
#include "dlfcn.h"
int main(int argc, char **argv) {
void *handle;
double (*cosine)(double);
char *error;
handle = dlopen ("/lib/libm.so.6", RTLD_LAZY);
if (!handle) {
fputs (dlerror(), stderr);
exit(1);
}
cosine = dlsym(handle, "cos");
if ((error = dlerror()) != NULL) {
fputs(error, stderr);
exit(1);
}
printf ("%f\n", (*cosine)(2.0));
dlclose(handle);
}


The program should be compiled linking dl

gcc -o foo foo.c -ldl

Library constructor and destructor functions


Libraries should export initialization and cleanup routines using the gcc

__attribute__((constructor)) and
__attribute__((destructor)) function attributes.

Constructor routines are executed before dlopen returns (or before main() is started if the library is loaded at load time).
Destructor routines are executed before dlclose returns (or after exit() or completion of main() if the library is loaded at load time).

The C example prototypes for these functions are:
void __attribute__ ((constructor)) my_init(void);
void __attribute__ ((destructor)) my_fini(void);


Shared libraries must not be compiled with the gcc arguments ``-nostartfiles'' or ``-nostdlib''. If those arguments are used, the constructor/destructor routines will not be executed

Related commands:

ldd
Displays a list of the shared libraries each program requires. For example if your executable is a.out and you need to know what all libraries this a.out requires for operation you can invoke the command ldd as ldd a.out
In Linux, the environment variable LD_LIBRARY_PATH is a colon-separated set of directories where libraries should be searched for first, before the standard set of directories
Or it can be added in the configuration file /etc/ld.so.conf

ldconfig

creates the necessary links and cache (for use by the run-time linker, ld.so) to the most recent shared libraries found in the directories specified on the command line, in the file /etc/ld.so.conf, and in the trusted directories (/usr/lib and /lib). ldconfig checks the header and file names of the libraries it encounters when determining which versions should have their links updated. ldconfig ignores symbolic links when scanning for libraries.ldconfig should normally be run by the super-user as it may require write permission on some root owned directories and files. It is normally run automatically at bootup, from /etc/rc, or manually whenever new DLL's are installed.

nm :
The nm command can report the list of symbols in a given library. It works on both static and shared libraries. For a given library it lists the symbol names defined, each symbol's value, and the symbol's type. It can also identify where the symbol was defined in the source code (by filename and line number), if that information is available in the library (see the -l option).
The type is displayed as a letter lowercase means that the symbol is local, while uppercase means that the symbol is global (external). Typical symbol types include T (a normal definition in the code section), D (initialized data section), B (uninitialized data section), U (undefined; the symbol is used by the library but not defined by the library), and W (weak; if another library also defines this symbol, that definition overrides this one).

Related links/references:

[1]http://www.linuxjournal.com/article/6463
[2]
http://www.linuxjournal.com/article/1059
[3]
http://www-106.ibm.com/developerworks/linux/library/l-shobj/

Tuesday, May 24, 2005

Recovering root password

I forgot the root password of my linux machine and googled to get this solution that worked for me

boot with the linux rescue disk

give the command
chroot /mnt/sysimage
passwd (this changes the root password!)

Linux GRUB rescue

Just thought of keying in some of my experience with Linux here to be of use for the community(acutally it will be of use for me :) since i often forget out what i did that day)....
Will try to make this a list of linux tips for day to day linux administration/programming/kernel.

Today i got my MBR with GRUB corrupted found out how to reinstall

boot with the rescure CD for the distro(I am using Fedora core 2).The entire file system will be mounted in /mnt/sysimage

do
chroot /mnt/sysimage to become the root
then do grub-install /dev/hda1(disk partition)