This book is for all real gurus, for soon-to-be gurus and all other wannabe-gurus.
1. The kernel loads some bytes of the binary to start and tries to determine it's file type. Therefor, it calls a number of binary handlers (which try to detect their specific binary signature). Two are commonly called: First, it's the script handler. It matches if the binary starts with "#!", the so-called "shell bang". The script handler then copies the remaining rest of the very first (shell bang) line and starts whatever is mentioned there, plus the script's file name. Second, there is the ELF binary handler. If it finds the ELF signature, it calls the "interpreter" mentioned inside the ELF binary.
2. The ELF interpreter (it's only called an interpreter, it isn't in real life) is most of the time /lib/ld-linux.so.2, the dynamic loader of GNU's glibc. It's always the "library" with absolute path that is printed by "ldd /path/to/binary". Procedure is the same as for scripts: the "interpreter" is called with the binary to start as it's command line argument. That is, you can manually call the dynamic ELF interpreter by hand: /lib/ld-linux.so.2 /bin/ls
The interpreter's task is to finally link the program. Remember, it's dynamically linked. That said, it needs to load the binary into proper memory locations and do the same for all needed libraries. Proper addresses are partially coded into the binary, partially they're just calculated.
3. For speed (and resource) reasons, ld-linux.so.2 doesn't just load all the binary into RAM, but uses a trick. It calls mmap() to do some kind of projection of the binary. This way, the kernel "knows" where the file's parts need to be inside RAM, but may decide to load them as needed.
4. After all the executable's needed parts (the executable ("text") section, the data sections, constructors and destructors, ...), ld-linux.so.2 jumps to the libc's entry point within the program. libc then starts all constructors (if there are any) and finally calls the main() function, which is the programs starting function from the programmer's point of view.
Binutils are a set of low-level programs like assembler, linker, disassembler, ...
GCC is the "main" actor when compiling programs. It's the compiler who translates your C, C++, ..., program source code into architecture-specific assembler instructions, which are then build up to an executable by GNU binutils.
Glibc is a large blob of glue code, which tries to give it's best to hide kernel specific functions from you. You simply use always-the-same functions like read() etc., and glibc translates it to something the kernel can execute.
This way, you can do portable programming by only using libc calls, not (specific) kernel calls.
If there's already a Linux distribution available for your machine, just use the distribution's supplied tools.
However, if you need to start from scratch (possibly starting with porting the GNU toolchain to your architecture), then follow this long'n'hard way...
So, if you've got to debug a small's program semantics, then you're best off using ltrace. If you need to debug some misbehaviour in medium-sized applications, then have a try with strace. All other variants will either require GDB, or are just not debugable if you aren't into that program's source code.
Debugging heavy graphical applications (things like Mozilla or OpenOffice) is a real pain in the a*s. They'll do tons of useless I/O (eg. writing things to the X11 server or getting X11 events), but this massive amount of data can simply hide the small number of interesting calls...
Device names start with a two bytes long type ID (floppy, SCSI block device, network card, controller, ...). Third byte is channel number (esp. interesting for scsi), 4th byte is device ID within it's channel. After that, supplemental information (like partition number) shows up.
device name | description |
---|---|
dka0 | dk = block device, a = first (SCSI?) channel, 0 = SCSI-ID=0 |
dva0 | dv = floppy disk, a = first floppy disk controller, 0 = first floppy drive |
ewa0 | ew = network card, a = first network card bus, 0 = first network card. |
http://mail-index.netbsd.org/port-vax/1996/02/19/0006.html
Normally, a computer's firmware doesn't directly load an operating system. Instead, it starts a boot loader, which in turn needs to load the kernel image (and possibly other parts) and starts it afterwards.
milo is used on AlphaBIOS Alphas.
aboot is used on Alphas which offer SRM firmware.
amiload loads a Linux kernel from a running AmigaOS.
Booting over the network has several advantages. First, you can have a centralized archive of boot images, second you can test things in a simple manner without risking locally saved data, third it will allow you to use NFS-Root, which is especially interesting if you work on machines whose Linux port is in an early state...
If your computer's firmware uses a proprietary boot protocol, there's not all that much to setup in the first run. However, if it uses the long-standing bootp/dhcp + tftp variant, you need to boot in two steps: first get some IP configuration, second start downloading the OS image.
Quite a lot of non-ia32 machines do have firmware support for using the IP protocol stack. Therefor, they requite to have an useable IP configuration. Often, this can be done manually, but most machines also accept to get their IP configuration from a remote server.
BOOTP is a simple protocol defined by RFCs XXX and XXX and allows a server to give a specific IP address to a client (those are normally identified by their MAC address).
DHCP is basically the same as BOOTP (they're even binary compatible), but with a lot of extensions.
A client machine may also issue a reverse ARP query to the network. Normal ARP queries try to figure out a MAC address for a given IP address. RARP does the opposite: it asks for an IP address for a given (own) MAC address.
A directed ping is mostly used to configure small, embedded devices. The trick is to enter a target's MAC address (statically) into some computer's ARP cache. Then, you use this computer to ping the machine (to be configured) once. The source machine can send the ping packet because it already knows the client's MAC address. Once the client receives a non-broadcast ping, it can read it's own IP address off the ping packet.
TFTP is by far the most common way to deliver a boot image in a IP-based network (possibly after using bootp or DHCP).
RBoot (short for Remote Boot) is mostly used by early HP PA-RISC machines. Later firmware releases may also use bootp and TFTP, but I'm unsure on this...
MOP is one of the oldest boot protocols and used on early VAXstations as well as DECstations. It's not only about booting. You can also remotely control VAXen's and DECstation's consoles with this protocol suite, but matching client applications seem to be missing under Linux...
For BOOTP and DHCP support, I'd recommend to install ISC's dhcpd. It will handle both protocols.
rarpd responds to reverse ARP requests. It uses /etc/ethers (or NIS lookup, but that's not commonly installed) to get an IP address or a hostname. If a hostname is presented in /etc/ethers, the hostname is looked up regulary to get an IP address.
/etc/ethers uses a quite simple format. One entry per line, each consisting of an MAC address (with ':' separated, hex digits in upper case) and (separated by space or tab) IP-Address or hostname.
But before it responds (after having found a match in /etc/ethers), it also checks if it can find a boot image for the IP address found. This IP address is used in hex format, uppercase with no interpunctuation (like C0A80A0F for 192.168.10.15). rarpd tries to find this file in the /tftpboot/ directory and only responds if it is found there. A symlink is okay, too, even a stale one...
rbootd typically reads a file (/etc/rbootd.conf) containing pairs of ethernet addresses (upper/lower case is ignored, colons to separate octets, leading zero of an octet isn't needed to be noted) and a tt. This is the file which will be served (if you don't specify a file, chances are that you may specify the tt at the workstation's command prompt).
All those boot image's tts are relative to /var/lib/rbootd, so this directory contains all boot images.
There are several mopd variants available. I suggest you to use the one you can find at XXX. This one can read the ELF object format so you don't need to convert your freshly linked kernel image into proprietary MOP images (I'm not even sure if there are conversion programs available at all...).
Generally, mopd tries to delive files from the /tftpboot/mop/ directory. It doesn't use the client's supplied machine type ID, but the client's MAC address, plus the suffix ".SYS". The MAX address is expected to be with leading zeros and hex digits in lowercase. It also accepts symlinks, so keep the images' real names readable and supply proper symbolic links for all your MOP-booting clients.
This chapter is mostly about running Linux on non-ia32 (non-cheap and horribly broken, that is) hardware.
In the following discussion, I basically recommend the following, simple partition layout. You may want to create more partitions, but since most of the older computers aren't equipped with all that large hard disk drives, it's only a waste of needed space to have more partitions:
First, a small boot partition (mounted on /boot) to holt the kernel image(s). Note that you not only may need that for older ia32-style computers. Even other machines (Sparc32 systems come to mind) need it!
Next partition is a swap partition, size should depend on actual RAM size and the foreseen job for the box.
The third and last partition is ment to be the larges partition, containing the root filesyetem (thus, mounted on /).
Alphas do basically come along with two totally different firmware types. Most machines actually can switch between both. First, it's AlphaBIOS, which either looks like an old Windows 3.1, or like a simple ncurses-style menu-driven window-system. If you have this firmware running, you need to use PC-BIOS partition layout and you'll need a separate, small partition holding the milo boot loader as well as the kernel image.
If you've got an Alpha using SRM firmware (you'll have textmode with blue background and ">>> " prompt), you need to use BSD slices as partition layout. Also, aboot is the boot loader of choice.
For VAX computers, there isn't yet a real boot loader available. Simply load the kernel image through MOP or dd or cat a properly compiled kernel image to the HDD's start, as you may be used to when creating bootable floppy disks.
Older PA-RISC machines use rboot for booting over the network. Newer machines may also support bootp/dhcp/tftp, but I haven't had access to today's PA-RISCs...
Additionally to that, PA-RISCs also boot off CD-ROM drives (and eventually even from SCSI tapes). This is particularly useful if your PA-RISC only got exotic network interfaces that you can't easily serve connectivity for (like FDDI).
Older machines only boot ECOFF kernel images, newer firmware versions support ELF images.
PowerPCs are a quite large family of computers. They start with small 32bit laptops and older Macintosh computers and find their end in IBM's fastest RS/6000 ("RISC SYSTEM") boxes.