Linux 版 (精华区)
发信人: netiscpu (说不如做), 信区: Linux
标 题: [B] Red Hat Linux Unleashed (52)
发信站: 紫 丁 香 (Sat Jul 25 05:03:44 1998), 转信
Working with the Kernel
_________________________________________________________________
o Upgrading and Installing New Kernel Software
o Compiling the Kernel from Source Code
o Adding Drivers to the Kernel
o Upgrading Libraries
o Developing Modules
o The Red Hat Live File System
o An Introduction to the Linux Source Tree
o A Brief Introduction to ELF
o Summary
_________________________________________________________________
52
Working with the Kernel
This chapter will look at:
* How to install and recompile the kernel of Linux
* How to add new software to the kernel
* How to install new versions of the shared libraries
* The steps necessary to create a new Linux kernel
Usually, you will want to leave the kernel alone, except when you are
performing a major upgrade or installing a new device driver that has
special kernel modifications. The details of the process are usually
supplied with the software. However, this chapter gives you a good
idea of the general process.
Few people will want to change the details in the kernel source code,
because they lack the knowledge to do so (or have enough knowledge to
know that hacking the kernel can severely damage the system). However,
most users will want to install new versions of Linux, add patches, or
modify the kernel's behavior a little.
______________________________________________________________
NOTE: Don't modify the kernel unless you know what you are doing.
If you damage the source code, your kernel may be unusable—and
in the worst cases, your file system may be affected. Take care and
follow instructions carefully. You need to know several things
about kernel manipulation, and this chapter looks at only the
basics.
______________________________________________________________
Several versions of Linux are commonly used, with a few
inconsistencies between them. For that reason, the exact instructions
given here may not work with your version of Linux. However, the
general approach is the same, and only the directory or utility names
may be different. Most versions of Linux supply documentation that
lists the recompilation process and the locations of the source code
and compiled programs.
Before you do anything with the kernel or utilities, make sure you
have a good set of emergency boot disks, and preferably, a complete
backup on tape or diskette. Although the process of modifying the
kernel is not difficult, every now and then it does cause problems
that can leave you stranded without a working system. Boot disks are
the best way to recover, so make at least one extra set.
Upgrading and Installing New Kernel Software
Linux is a dynamic operating system. New releases of the kernel, or
parts of the operating system that can be linked into the kernel, are
made available at regular intervals to users. Whether or not you want
to upgrade to the new releases is up to you and usually depends on the
features or bug fixes that the new release offers. You will probably
have to recompile and relink the kernel when new software is added,
unless it is loaded as a utility or device driver.
You should avoid upgrading your system with every new release, for a
couple of reasons. The most common problem with constant upgrades is
that you may be stuck with a new software package that causes backward
compatibility problems with your existing system or that has a major
problem with it that was not patched before the new software was
released. This can cause you no end of trouble. Most new software
releases wipe out existing configuration information, so you have to
reconfigure the packages that are being installed from scratch.
Another problem with constant upgrades is that the frequency with
which new releases are made available is so high that you can probably
spend more time simply loading and recompiling kernels and utilities
than actually using the system. This becomes tiresome after a while.
Because most major releases of the Linux operating system are
available, the number of changes to the system is usually quite small.
Therefore, you should read the release notes carefully to ensure that
the release is worth the installation time and trouble.
The best advice is to upgrade only once or twice a year, and only when
there is a new feature or enhancement to your system that will make a
significant difference in the way you use Linux. It's tempting to
always have the latest and newest versions of the operating system,
but there is a lot to be said for having a stable, functioning
operating system.
If you do upgrade to a new release, bear in mind that you don't have
to upgrade everything. The last few Linux releases have changed only
about five percent of the operating system with each new major package
upgrade. Instead of replacing the entire system, just install those
parts that will have a definite effect, such as the kernel, compilers
and their libraries, and frequently used utilities. This saves time
and reconfiguration.
Compiling the Kernel from Source Code
Upgrading, replacing, or adding new code to the kernel is usually a
simple process: you obtain the source for the kernel, make any
configuration changes, compile it, and then place it in the proper
location on the file system to run the system properly. The process is
often automated for you by a shell script or installation program, and
some upgrades are completely automated—you don't need to do
anything except start the upgrade utility.
Kernel sources for new releases of Linux are available from CD-ROM
distributions, FTP sites (see Appendix A, "Linux FTP Sites and
Newsgroups"), user groups, and many other locations. Most kernel
versions are numbered with a version and a patch level, so you will
see kernel names such as 1.12.123, where 1 is the major release, 12 is
the minor version release, and 123 is the patch number. Most sites of
kernel source code maintain several versions simultaneously, so check
through the source directories for the latest version of the kernel.
Patch releases are sometimes numbered differently and do not require
the entire source of the kernel to install. They just require the
source of the patch. In most cases, the patch overlays a section of
existing source code, and a simple recompilation is all that's
necessary to install the patch. Patches are released quite frequently.
Most kernel source programs are maintained as a gzipped tar file.
Unpack the files into a subdirectory called /usr/src, which is where
most of the source code is kept for Linux. Some versions of Linux keep
other directories for the kernel source, so you may want to check any
documentation supplied with the system or look for a README file in
one of the three /usr/src subdirectories, linux, linux-1.2.13, or
redhat for more instructions.
Often, unpacking the gzipped tar file in /usr/src creates a
subdirectory called /usr/src/linux, which can overwrite your last
version of the kernel source. Before starting the unpacking process,
rename or copy any existing /usr/src/linux (or whatever name is used
with the new kernel) so you have a backup version in case of problems.
After the kernel source has been unpacked, you need to create two
symbolic links to the /usr/include directory, if they are not created
already or set by the installation procedure. Usually, the link
commands required are
ln -sf /usr/src/linux/include/linux /usr/include/linux
ln -sf /usr/src/linux/include/asm /usr/include/asm
If the directory names shown are different from your version of Linux,
substitute the new directory names for /usr/src/linux. Without these
links, the upgrade or installation of a new kernel cannot proceed.
After the source code has been ungzipped and untarred and the links
have been established, the compilation process can begin. You must
have a version of gcc or g++ (the GNU C and C++ compilers) or some
other compatible compiler available for the compilation. You may have
to check with the source-code documentation to make sure you have the
correct versions of the compilers; occasionally, new kernel features
are added that are not supported by older versions of gcc or g++.
Check the file /usr/src/linux/Makefile (or whatever path the Makefile
is in with your source distribution). There will be a line in the file
that defined the ROOT_DEV, which is the device that is used as the
root file system when Linux boots. Usually the line looks like this:
ROOT_DEV = CURRENT
If you have any other value, make sure it is correct for your
file-system configuration. If the Makefile has no value, set it as
shown in the preceding code line.
______________________________________________________________
NOTE: It's a good idea to run make clean; make depend; make
mrproper before rebuilding the kernel to make sure all old files
are removed.
______________________________________________________________
The compilation process begins when you change to the /usr/src/linux
directory and issue the following command:
make config
This command invokes the make utility for the C compiler. The process
may be slightly different for some versions of Linux, so you should
check with any release or installation notes supplied with the source
code.
______________________________________________________________
NOTE: Be sure that you are running either /bin/bash or /bin/sh
before you run make. Running another shell such as tcsh may cause
you problems with the make files.
______________________________________________________________
The config program issues a series of questions and prompts that you
need to answer to indicate any configuration issues that need to be
completed before the actual compilation begins. These may be about the
type of disk drive you are using, the CPU, any partitions, or other
devices, such as CD-ROMs. Answer the questions as well as you can. If
you are unsure, choose the default values or the choice that makes the
most sense. The worst case is that you might have to redo the process
if the system doesn't run properly. (You do have an emergency boot
disk ready, don't you?)
Next, you have to set all the source dependencies. This is a step that
is commonly skipped, and it can cause several problems if it is not
performed for each software release. Issue the command
make dep
If the software you are installing does not have a dep file, check
with the release or installation notes to ensure that the dependencies
are correctly handled by the other steps.
After that, you can finally compile the new kernel. The command to
start the process is
make zImage
make zdisk
make zlilo
This compiles the source code and leaves the new kernel image file in
the current directory (usually /usr/src/linux). The make zdisk is
really necessary for creating a boot disk, and therefore expects a
blank, unformatted disk in the floppy drive and will ask you for one
as it runs. Not all releases or upgrades to the kernel support
compressed image compilation.
The last step in the process is to copy the new kernel image file to
the boot device or a boot floppy. Use the following command to place
the file on a floppy:
cp Image /dev/fd0
To be safe, copy the old kernel to a known image and then copy the
newly created image to the root. This would be accomplished with these
two commands:
mv /vmlinuz /vmlinuz.oldcp /usr/src/linux/arch/i386/boot/zImage /vmlinuz
Now all that remains is to reboot the system and see if the new kernel
loads properly. If there are any problems, boot from a floppy, restore
the old kernel, and start the process again. Check the documentation
supplied with the release source code for any information about
problems you may encounter or steps that may have been added to the
process.
Adding Drivers to the Kernel
You may want to link in new device drivers or special software to the
kernel without going through the upgrade process of the kernel itself.
This is often necessary when you add a new device to the system, such
as a multiport board or an optical drive, that should be loaded during
the boot process. Alternatively, you may be adding special security
software that must be linked into the kernel.
The add-in kernel software usually has installation instructions
provided, but the general process is to locate the source in a
directory that can be found by the kernel-recompilation process (such
as the /usr/src directory). To instruct the make utility to add the
new code to the kernel, you often need to modify the Makefile. These
modifications may be performed manually or by an installation script.
Some software has its own Makefile supplied for this reason.
At this point, it's time to begin the kernel recompilation with the
new software added into the load. The process is the same as shown in
the preceding section; the kernel is installed in the boot location or
set by LILO. Typically, the entire process takes about 10 minutes and
is quite trouble-free, unless the vendor of the kernel modification
did a sloppy job. Make sure that the source code provided for the
modification will work with your version of the Linux kernel by
reading any text files that accompany the code and
software-compatibility files included with most distributions of
Linux.
The latest version numbers to look for are found in the newsgroup
discussions. To see the version of kernel source tree to build your
kernel, use the command: uname -a. The version number of your kernel
should be 1.2.13 or higher.
Upgrading Libraries
Most of the software on a Linux system is set to use shared libraries
(a set of subroutines used by many programs). When you see the message
Incompatible library version
displayed after you have performed an upgrade to the system and you
try to execute a utility, it means that the libraries have been
updated and need to be recompiled. Most libraries are backward
compatible, so existing software should work properly even after a
library upgrade.
Library upgrades occur less frequently than kernel upgrades, and you
can find them in the same places. There are usually documents that
guide you to the latest version of a library, or there may be a file
explaining which libraries are necessary with new versions of the
operating system kernel.
Most library upgrades are gzipped tar files, and the process for
unpacking them is the same as for kernel source code—except that
the target directories are usually /lib, /usr/lib, and /usr/include.
Usually, any files that have the extension .a or .aa go in the
/usr/lib directory. Shared library image files, which have the format
libc.so.version, are installed into /lib.
You may have to change symbolic links within the file system to point
to the latest version of the library. For example, if you are running
library version libc.so.4.4.1 and upgrade to libc.so.5.2.18, you must
remove the old link and reset the symbolic link set in /lib to this
libc.so.5.2.18 file. The command is:
ln -sf /lib/libc/so/4/4/1 /lib/libc.so.5.2.18
where the last filename in the link command is the name of the current
library file in /lib. Your library name may be different, so check the
directory and release or installation notes first.
You would also need to change the symbolic link for the file
libm.so.version in the same manner. Do not delete the symbolic links;
all programs that depend on the shared library (including ls) would be
unable to function without them.
Developing Modules
A module is an object file that is loaded at runtime by the Linux
kernel. Modules offer a bit of functionality that does not have to be
loaded in memory all the time. When a particular function in a module
is found, the Linux kernel will load it in. Types of modules include,
but are not limited to, the following:
* Tape module via the ftape module
* PPP/SLIP modules
* CD-ROM modules
First check to see if your kernel supports modules. To do this, run
the make config command and see what the default response to the
question of "dynamic loading support" is. If the answer to this
question is not Yes, you should answer Yes, and then rebuild, install,
and boot from a new kernel. If the system already supports modules,
you can begin with the next step of making modules.
To make the modules on your system, go to /usr/src/linux directory and
run the two commands:
make modules
make modules_install.
Be prepared to wait a while.
To list the current modules in your kernel, use the lsmod command. To
insert a module, use the command insmod moduleName. To remove a
module, use the command rmmod moduleName. Modules can be loaded
automatically by placing the commands to load them in the
/etc/rc.d/rc.sysinit file.
The Red Hat Live File System
Red Hat offers a "live" file system on CD-ROM. If you are short on
disk space or do not want the entire Red Hat distribution on your hard
drive, you can run off the CD-ROM with the "live" file system. It's
easy to mount the CD-ROM as an extension of the file system with the
command:
mount -t iso9660 /dev/cdrom /mntFS
From then on the CD-ROM will be accessed under the /mntFS directory.
To check out the source files, and so on for your Red Hat distribution
you would look in the directory /mntFS/live/usr/src/linux. The Red Hat
subdirectory under the /mntFS/live/usr/src/ directory is empty. (An
oversight you ask? No, if you buy the official version from Red Hat
you get a second CD with the source tree on it!)
There are only a few subdirectories under the live file system. These
directories are listed here relative to the /mntFS/live tree:
total 145
drwxrwxr-x 16 root root 2048 Mar 6 13:53 .
drwxr-xr-x 6 root root 2048 Mar 6 13:32 ..
-r—r—r— 1 root root 586 Mar 6 14:10 TRANS.TBL
drwxr-xr-x 2 root root 8192 Mar 6 13:45 bin
drwxr-xr-x 2 root root 2048 Mar 6 13:45 boot
drwxr-xr-x 3 root root 77824 Mar 6 13:45 dev
drwxr-xr-x 11 root root 12288 Mar 6 13:45 etc
drwxr-xr-x 6 root root 2048 Mar 6 13:45 home
drwxr-xr-x 3 root root 6144 Mar 6 13:45 lib
drwxr-xr-x 2 root root 2048 Mar 6 13:32 lost+found
drwxr-xr-x 4 root root 2048 Mar 6 13:45 mnt
dr-xr-xr-x 29 root root 6144 Mar 6 13:46 proc
drwxr-xr-x 4 root root 2048 Mar 6 13:46 root
drwxr-xr-x 2 root root 10240 Mar 6 13:46 sbin
drwxrwxrwx 3 root root 2048 Mar 6 13:46 tmp
drwxr-xr-x 19 root root 4096 Mar 6 13:45 usr
drwxr-xr-x 13 root root 2048 Mar 6 13:46 var
Most of these subdirectories are not as heavily populated as the root
directory of a hard disk installed system.
Running off the CD-ROM may save you disk space, but it certainly does
not save you time. Also, you cannot configure some important files in
directories off the mount point. The inability to read/write certain
directories even as root may cause some system administrative scripts
to fail.
Also, the performance of the system when run from the CD-ROM on a 486
DX4, with 32MB of RAM, was slow. Really, there should be no need to
run any serious application by running off the CD-ROM. You can install
fewer components if you have to. Actually running off the CD-ROM is
very slow and really intended for trying out packages and loading
files from your CD-ROM. Do not attempt to run off the CD-ROM even if
you have a 6X drive since the performance will be very slow.
Also, keep in mind that to run off the CD-ROM you will need to create
boot disks as described in the first three chapters of this book. The
image to use for CD-ROM boot capability for the RAM disk is called
liveram.img. In addition to the RAM disk, you will have to have a
blank, formatted disk to use as your data repository. Please refer to
the installation sections in the first three chapters of this book on
how to create boot and ram disks. Please see Chapter 4, "LILO," for
more information.
An Introduction to the Linux Source Tree
The Linux source code can be found in the /usr/src/linux directory.
You will need to look at the source code if you want to make
enhancements to the kernel. For the reader interested in kernels, this
directory is a very good reference.
The first point to start is to look in the /usr/src/include directory
and see what header files you have available. This way you can tell
what system services are available. (See Table 52.1.) I have
deliberately left out redundant, old, or unused headers files. By
examining the header files, you can see what files and systems are
available in Linux.
Table 52.1. Linux header files.
FILE Description
a.out.h Generated for the GNU C compilers.
autoconf.h Automatically generated C config file, don't edit it!
aztcd.h Definitions for an AztechCD268 CD-ROM interface.
binfmts.h Binary formats for the files.
bios32.h BIOS32, PCI BIOS functions and defines.
blkdev.h Block device information.
busmouse.h Header file for Logitech Bus Mouse driver.
cdrom.h General header for all CD-ROM drives.
cdu31a.h Definitions for a Sony interface CD-ROM drive.
coff.h The COFF file format definitions.
config.h Linux kernel configuration header.
ctype.h Standard C types header.
cyclades.h For the Cyclades devices.
debugreg.h Debug registers header file.
delay.h Delay routines for precomputed loops_per_second value.
elf.h The Executable and Linking format definitions.
errno.h The standard error return definitions.
etherdevice.h Ethernet device handlers declarations.
ext2_fs.h The new extended filesystem (e2fs) declarations.
ext_fs.h The ext filesystem (efs) definitions, older linux.
fcntl.h The standard file control declaration.
fd.h Floppy disk software control definitions.
fdreg.h Some defines for the floppy disk controller itself.
fs.h Definitions for some important file table structures.
genhd.h Generic hard disk header declarations.
hdreg.h Declarations for the AT hard disk controllers.
head.h Intel's Global and Interrupt Descriptor Table.
hpfs_fs.h The HP file system information.
icmp.h Definitions for the ICMP protocol.
if.h Definitions for the INET interface module.
if_arp.h Definitions for the ARP (RFC 826) protocol.
if_ether.h Definitions for the Ethernet IEEE 802.3 interface.
if_plip.h PLIP tuning facilities for the new Niibe PLIP.
if_slip.h Special use with the SLIP/CSLIP/KISS TNC driver.
igmp.h Internet Gateway Management Protocol (IGMP).
in.h Definitions of the Internet Protocol.
in_systm.h Miscellaneous internetwork definitions for kernel.
inet.h Internet Protocol headers.
interrupt.h For Linux interrupt drivers.
ioctl.h Standard IO control definitions.
ioport.h For detecting, reserving, allocating system resources.
ip.h Definitions for the IP protocol.
ipc.h For Interprocess communication
ipx.h For sockets in network programming.
iso_fs.h The ISO file system headers.
kd.h Kernel development declarations.
kernel.h Kernel header file declarations.
kernel_stat.h More Kernel statistics header file declarations.
keyboard.h Declaration for using the keyboard.
ldt.h Definitions for use with Inter Local Descriptor Tables.
limits.h Limits for the kernel to use.
linkage.h Linking declarations for the kernel.
locks.h File locking definitions.
lp.h Line Printer support header.
major.h Major device number header.
malloc.h Standard memory management function header.
math_emu.h Math emulation declarations.
mc146818rtc.h Register definitions for RealTime Clock and CMOS RAM.
mcd.h Definitions for a Mitsumi CD-ROM interface.
minix.h The minix filesystem constants/structures.
mm.h Memory manager for kernel.
mman.h Memory Mapping definitions.
module.h Dynamic loading of modules into the kernel.
mouse.h Serial mouse.
msdos_fs.h The MS-DOS file system constants/structures.
msg.h For message processing in Linux IPC.
param.h Internal Linux parameters header.
pci.h PCI bus defines and function prototypes.
personality.h Linux file personality declarations.
pipe_fs_i.h For use with Linux file pipes.
ppp.h For use with Point-To-Point Protocol with Linux.
proc_fs.h The proc file system constants/structures.
ptrace.h Defines to help the user use the ptrace system call.
resource.h Resource control/accounting header file for Linux.
route.h Global definitions for the IP router interface.
sbpcd.h For Panasonic CD-ROMs.
sched.h The Linux task scheduler.
scsicam.h SCSI RAM support functions, use for HDIO_GETGEO, and so on.
sem.h For use with semaphores on Linux.
serial.h Linux serial IO definitions.
serial_reg.h For the UART port assignments.
shm.h For shared memory use on Linux.
signal.h For Linux signal information.
skbuff.h For the 'struct sk_buff' memory handlers.
socket.h The socket-level I/O control calls.
sockios.h More of the socket-level I/O control calls.
sonycd535.h Commands for the CD-ROMs by Sony (CDU-531-5).
soundcard.h For interfacing with Soundcards.
stat.h Standard C and UNIX definitions.
stddef.h Standard C definitions.
string.h String functions declarations for C programmers.
symtab_begin.h Symbol table entries.
symtab_end.h Symbol table entries.
sys.h All system call entry points.
sysv_fs.h The SystemV/Coherent file system definitions.
tasks.h Specifying the max number of tasks at one time in Linux.
tcp.h Definitions for the TCP protocol.
termios.h Terminal IO declarations.
time.h Standard declarations for use with timers.
timer.h Do not modify this timer declarations file.
times.h For use with Linux kernel timers.
timex.h For TIMEX devices.
tpqic02.h Include file for QIC-02 driver for Linux.
tqueue.h The task queue handling information for Linux.
tty.h Defines some structures used by tty_io.c.
tty_driver.h Interface between low-level tty driver and kernel.
types.h Standard Linux types.h file.
udp.h Definitions for the UDP protocol.
ultrasound.h For Ultrasound CD-ROM devices.
umsdos_fs.h The UMSDOS file system header.
un.h Linux header for socket programming.
unistd.h Standard UNIX file header.
user.h For use with core dumps and user segments.
utime.h Time information.
utsname.h Time information and structures.
version.h Linux version information.
vfs.h Virtual file system headers.
vm86.h Virtual memory management routines.
vt.h For use with virtual terminals.
xd.h Definitions for IO ports, and so on, for XT hard controllers.
Let's give an example of how you would use this header file
information. Let's say that in the default kernel for the sbcpd
(Panasonic CD-ROM) drive, it takes very long for it boot since it
probes the IO ports to see where the drive is in the IO port memory
space. You know you have set your jumpers on the drive to 0x260, why
not just have it look there and keep going. You are sick of typing in
the sequence every time you boot: sbpcd=0x260,SoundBlaster Sounds
good. Let's look at the sbpcd.h file in /usr/src/linux/include/linux.
First become root and make sure that you have write privileges to this
header file to save your changes to. Look at the part of the file
where it says to define your CD-ROM port base address as CDROM_PORT
and specify the type of your interface card as SBPRO. So you can
change the address lines in file after line 90 as the following:
#undef CDROM_PORT /* get rid of previous declarations. */
#undef SBPRO /* get rid of previous declarations. */
#undef SOUND_BASE /* get rid of previous declarations. */
/* override these values. */
#define CDROM_PORT 0x230 /* <<< port address */
#define SBPRO 0 /* <<< interface type * /
#define SOUND_BASE 0x220 /* <<< sound address of this card or 0 */
Now get out of the editor after making the changes. Rebuild the kernel
and install it as discussed earlier in this chapter. Reboot and there
you have it—a fast boot.
This is only a quick example of how to use the valueable resource of
information to customize your Linux system. I am sure that with some
exploring you can come across some more examples.
A Brief Introduction to ELF
The Executable and Linking Format (ELF) has become a hot topic for
Linux users lately. All major releases of the Linux kernel and
libraries will support the ELF format in the future. The general idea
is that ELF will be the common object file format for all Linux
binaries. The public release of all ELF file format compatible
compilers are here with the kernel on the CD-ROM, and hopefully with
the future releases of Linux.
First of all, the current shared libraries are a bit bulky to manage.
When you are dealing with large packages such as the X Window System
that span a big tree hierarchy, building and maintaining such a
library is a formidable task. Also, the a.out shared library scheme
does not support the dynamic load function: dlopen().
So what's the big deal about ELF? The general UNIX programming
community seems to like this file format. In fact, several commercial
versions of UNIX, such as Solaris and Unixware already use ELF. More
vendors such as SCO, HP are moving to towards supporting it in the
future. (By the way, Microsoft's NT is not based on ELF.) There is no
reason why the Linux community should be left behind.
There are three basic types of ELF files: object (.o) files, a.out
executables and shared libraries. Even though functionally the three
types of files perform different functions, internally they are very
similar in structure. One common part in all different ELF file types
(including a.out and other executable file formats) is the idea of a
section. A section represents a portion of the file containing a set
of related information. A binary image of a file consists of many
sections. For example, executable code is always placed in a section
known as .text, all data variables initialized by the user are placed
in a section known as .data, and uninitialized data is placed in a
section known as .bss (historically known as Below Stack Segment).
Dividing executables into sections has many important advantages. For
example, once you have loaded the executable portions of an executable
into memory, the values at these memory locations need not change.
Unless of course you happen to be of the twisted mentality that
actually modifies code while it's executing. Executable code which
could modify itself is considered a dispicable programming practice in
most cases.
Given this set of code segments, the memory manager on a machine can
set aside portions of memory as read-only. Thereafter any attempt to
modify a read-only memory location will result in a core dump. So all
attempts to modify read-only memory are considered fatal errors.
Rather than set individual bits of memory and slow the computer down,
you can set bits on portions of memory known as pages. (On an Intel
386 machine, a page is 4096 bytes long.) Pages are normally set at
1024 byte multiples since most paging systems work on 1024 byte
boundaries. This was the reason to switch from the ZMAGIC file format
to the QMAGIC format in ELF files. Both formats have a 32-byte header
at the start of the file, but with ZMAGIC the .text section starts at
byte offset 1024 followed by a header. The QMAGIC .text section
includes the header and starts at the beginning of the file. ZMAGIC
took up more space than QMAGIC and did not page easily since it was
not on a 1024 byte boundary. A 1024 byte boundary makes items easily
cache-able with the current Linux buffering scheme.
For program security and consistency, we want all executable parts in
read-only memory and all modifiable data locations in writable memory.
The read-only memory is therefore sacrosanct from erroneous memory
updates. It's efficient to group all of the executable portions
together in one section (.text) and all modifiable data areas together
into another area of memory (.data). Data sections are further divided
into two sections: uninitialized data (.bss) and initialized data
(.data). The .bss section is different from .data because .bss doesn't
take up space in the file, it only tells how much space will be needed
for uninitialized variables.
When the kernel starts to load and run an executable, it looks at the
image header on what to do when loading the image. First the kernel
locates the .text section within the executable, then loads them into
memory and then marks these executeable memory pages as read-only to
prevent self-modifying code The kernel then locates the .data section
in read-write memory. After that loading and initializing .data, the
kernel allocates space for, and loads the .bss section. (The Linux
kernel will zero out the .bss section by default.)
Each a.out or ELF file also includes a symbol table, which is a list
of all of the symbols in the program. A symbol is a named address of a
program entry point or a variable, and more. Symbols are defined or
referenced within the file. Information about a symbol in the symbol
table contains the address associated with the symbol, and some kind
of tag indicating the type of the symbol at the minimum. ELF files
have considerably more information per symbol than a.out file.
Symbol information is critical when debugging files. However, the size
of the executeable file is greater than it has to be. You can remove
symbol tables the strip utility. The advantage is that the final
executable is smaller once stripped. The disadvantage is that you lose
the ability to debug the stripped binary. With a.out it is always
possible to remove the symbol table from a file, but with ELF you
typically need some symbolic information in the file for the program
to load and run. So in an ELF image, the strip program will always
leave some symbolic information behind.
Now let's see the topic of relocation. First compile a program with
the following line in it:
printf("Hello World\n");
The compiler will generate an object file which contains a reference
to the function printf. Since your program has not defined this
symbol, it is an external reference. The executable object code for
program will contain an instruction to call printf, but in the object
code we do not yet know the actual location to call to perform this
function. The compiler will generate assembler code which in turn will
be passed to the assembler portion for conversion where a relocation
reference will be generated.
A relocation reference contains three major components: One is an
index into the symbol table, so the kernel loader will symbol to what
is being referenced and the other is an offset into the .text section,
which refers to the address of the operand of the call instructions.
The third component is a tag of the type of relocation. When gcc links
this file, its linker will resolve the relocations by patching the
external references into library text sections. The output from this
process after the linker will be the a.out file (unless you specified
a different name with -o name option). An a.out executable will
therefore not have any relocations. The kernel loader, ld, cannot
resolve such symbols and will not run such a binary.
So how's the ELF format different from the a.out format? Let's look at
a.out formats first. First, the header of an a.out file (look at
struct exec, defined in /usr/src/linux/include/linux/a.out.h) contains
only allows the .text, .data, and .bss sections and does not directly
support any additional sections. Two, a.out contains only the sizes of
the various sections not the offsets of where they are in the file
since the offsets are predefined constants. Also, there is no built-in
shared library support. The a.out format was developed before shared
library technology was developed, so shared libraries are not very
cleanly supported. It is not impossible to design shared library
implementations that work with a.out. ELF allows us to discard some of
the hacks that were required to piggyback a shared library
implementation onto a.out.
Now let's look a little bit at what a shared library is. Non-shared
libraries (also known as static libraries) contain common useful
procedures callable from programs. When you link against a static
library, the linker must extract all library functions you require and
make them part of your executable making it bulky.
A shared library lets you take a static version of library and
pre-link it into some kind of special type of executable. When you
link your program against the shared library, the linker does not
extract the binary code from shared library into your executeable,
rather it simply adds a reference to the code's offset and the library
to use. After linking, when the loader runs your program, it knows
where to get the code from which library to fill in any memory gaps.
With the current a.out scheme, shared libraries must be loaded in
predefined locations in memory. ELF shared libraries are position
independent. This means that you can load them at just about any
location in memory to get them to work. ELF shared libraries have to
be compiled with -fPIC switch to generate position independant code.
When you compile something to be -fPIC, the compiler reserves one
machine register (register ebx on the i386) to point to the start of a
global offset table (GOT). The cost is that this register is reserved
by the compiler and results in less flexibility in optimizing code.
ebx register in an i386 machine is not very popular so it's not that
big a loss in speed.
Another ELF feature is that its shared libraries resolve symbols and
externals at run time by using a symbol table and a list of
relocations. Symbol resolution is performed before the image executes.
The ELF support in Linux makes it very efficient since all symbols are
referenced off the same global variable for the ELF library, rather
than a fixed location in memory. Basically each global variable
defined or referenced in the shared library means that the kernel uses
the ebx register to compute and load the address of the variable from
the GOT to get the address. The advantage of using one global variable
is that when the loader ld moves an entire .text or .data section, you
need only resolve one global address and do no address resolutions.
A similar setup is used for functions with the use of a Procedure Link
Table (PLT). The use of the PLT enables the programmer to redefine
(override) functions which might be in the shared library. Then the
PLT entry for the function can be used instead of the regular library
entry. A PLT is only an array of jump instructions, one for each
function that you might need to go to. Thus if a particular function
is called from many positions within the shared library, the call will
always pass through one jump instruction. You can then control all
calls to this file by setting or resetting this one location register.
Efficient and clean.
This chapter cannot possibly cover all you need to know about the ELF
format. For more information about the ELF file format, obtain the ELF
specifications from a number of sources—for example
ftp.intel.com">ftp.intel.com in pub/tis/elf11g.zip.
The specifications are also available in a printed format. See SYSTEM
V Application Binary Interface (ISBN 0-13-100439-5) and SYSTEM V
Application Binary Interface, Intel386 Architecture Processor
Supplement (ISBN 0-13-104670-5).
Summary
Recompiling kernel source and adding new features to the kernel
proceeds smoothly, as long as you know what you are doing. Don't let
the process scare you, but always keep boot disks on hand. Follow
instructions wherever available, because most new software has special
requirements for linking into the kernel or replacing existing
systems.
--
Enjoy Linux!
-----It's FREE!-----
※ 修改:.netiscpu 于 Jul 25 06:05:58 修改本文.[FROM: mtlab.hit.edu.cn]
※ 来源:.紫 丁 香 bbs.hit.edu.cn.[FROM: fengyun.hit.edu.]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:624.315毫秒