Linux Assembly Tutorial

Quickstart

Written by: Derick Swanepoel (derick@maple.up.ac.za)
Version 1.0 - 2002-04-19, 01:50am

Download as zipfile

JMP Step-by-Step Guide

Contents

1. Intro
2. Comparison of a Linux assembly program and a DOS assembly program
3. More About Linux System Calls
4. Command Line Arguments and Writing to a File
5. Compiling and Linking

1. Intro

This Quickstart aims to show you the ropes on Linux assembly as quickly as possible. Basically, it just points out the differences between a Linux and DOS assembly program with just enough explanation not to confuse you. For more detail and why things are the way they are, see the Step-by-Step Guide.

2. Comparison of a Linux assembly program and a DOS assembly program

Linux DOS




SECTION .DATA
	hello:     db 'Hello world!',10
	helloLen:  equ $-hello

SECTION .TEXT
	GLOBAL _START

_START:



	; Write 'Hello world!' to the screen
	mov eax,4            ; 'write' system call
	mov ebx,1            ; file descriptor 1 = screen
	mov ecx,hello        ; string to write
	mov edx,helloLen     ; length of string to write
	int 80h              ; call the kernel

	; Terminate program
	mov eax,1            ; 'exit' system call
	mov ebx,0            ; exit with error code 0
	int 80h              ; call the kernel

DOSSEG
.MODEL LARGE
.STACK 200h

.DATA
	hello      db 'Hello world!',10,13,'$'
	helloLen   db 14

.CODE
	ASSUME CS:@CODE, DS:@DATA

START:
	mov ax,@data
	mov ds,ax

	; Write 'Hello world!' to the screen
	mov ah,09h            ; 'print' DOS service
	mov dx,offset hello   ; string to write
	int 21h               ; call DOS service



	; Terminate program
	mov ah,4Ch            ; 'exit' DOS service
	mov ax,0              ; exit with error code 0
	int 21h               ; call DOS service
END START
Compiling: nasm -f elf hello.asm
Linking: ld -s -o hello hello.o
Compiling: tasm hello.asm
Linking: tlink hello.obj

Lets compare each part in the two programs:

In this case it looks like it's more work than in DOS, but when it comes to creating, reading and writing files, Linux syscalls are much easier to use than their DOS counterparts.

3. More About Linux System Calls

There are six registers that are used for the arguments that a system call takes. The first argument goes in EBX, the second in ECX, then EDX, ESI, EDI, and finally EBP, if there are so many. If there are more than six arguments, EBX must contain the memory location where the list of arguments is stored.

All the syscalls are listed in /usr/include/asm/unistd.h, together with their numbers. However, for your convenience you can simply find them in this Linux System Call Table, together with some other useful information (eg. what arguments they take). The syscalls are fully documented in section 2 of the manual pages, so you can just go man 2 write to find out what the write syscall does, what arguments it takes, etc.

4. Command Line Arguments and Writing to a File

Linux
section .data
	hello     db	'Hello, world!',10	; Our dear string
	helloLen  equ	$ - hello		; Length of our dear string

section	.text
    global _start

_start:
	pop	ebx		; argc (argument count)
	pop	ebx		; argv[0] (argument 0, the program name)
	pop	ebx		; The first real arg, a filename

	mov	eax,8		; The syscall number for creat() (we already have the filename in ebx)
	mov	ecx,00644Q	; Read/write permissions in octal (rw_rw_rw_)
	int	80h		; Call the kernel
				; Now we have a file descriptor in eax

	test	eax,eax		; Lets make sure the file descriptor is valid
	js	skipWrite	; If the file descriptor has the sign flag
				;  (which means it's less than 0) there was an oops,
				;  so skip the writing. Otherwise call the filewrite "procedure"
	call	fileWrite

skipWrite:
	mov	ebx,eax		; If there was an error, save the errno in ebx
	mov	eax,1		; Put the exit syscall number in eax
	int	80h		; Bail out

; proc fileWrite - write a string to a file
fileWrite:
	mov	ebx,eax		; sys_creat returned file descriptor into eax, now move into ebx
	mov	eax,4		; sys_write
				; ebx is already set up
	mov	ecx,hello	; We are putting the ADDRESS of hello in ecx
	mov	edx,helloLen	; This is the VALUE of helloLen because it's a constant (defined with equ)
	int	80h

	mov	eax,6		; sys_close (ebx already contains file descriptor)
	int	80h
	ret
; endp fileWrite
DOS
DOSSEG
.MODEL LARGE
.STACK 200h

.DATA
filename	db 14 dup (0)
filehandle	dw
hello		db 'Hello World!',10,13,'$'
helloLen	db 12

.CODE
ASSUME CS:@CODE, DS:@DATA

START:
	mov	AX,@DATA
	mov	ES,AX                  ; Point ES to the data segment for now

	mov	ah,62h
	int	21h                    ; Get the PSP
	mov	ds,bx
	mov	bx,81h                 ; Starting at the first printable character
	add	bl, byte ptr [ds:80h]  ; Get address of last character
	mov	cl, byte ptr [ds:80h]  ; Also put it in CL
	inc	cl
	mov	[ds:bx], word ptr 0    ; Null terminate the argument

	mov	si,81h
	mov	di,0                   ; Copy the first argument into the data segment
	rep	movsb                  ;  into the filename variable

	mov	AX,@DATA
	mov	DS,AX                  ; Point DS to the data segment, like normal

	call	fileCreate
	call	fileWrite
	call	fileClose

	mov	AX,4C00h
	int	21h                    ; Bye-bye!
END START

proc fileCreate
	mov	ah,3Ch                 ; Creat DOS service (yes, it is called 'creat')
	mov	cx,0                   ; File attributes
	mov	dx,offset filename     ; Put ADDRESS of filename in DX
	int	21h

	mov	[filehandle],ax        ; File handle is returned in AX, put in a variable
	ret
endp fileCreate

proc fileClose
	mov	ah,3Eh
	mov	bx,[filehandle]
	int	21h
	ret
endp fileClose

proc fileWrite
	mov	ah, 40h
	mov	bx, [filehandle]
	mov	dx, offset hello       ; ADDRESS of string to be written
	xor	cx, cx                 ; If I don't do this, things blow up in my face
	mov	cl, [helloLen]         ; VALUE of length of string to be written
	int	21h
	ret
endp fileWrite

As you can see, the Linux program is much simpler than the DOS one (40 lines in Linux, with liberal commenting, vs. 66 for DOS). Everything makes sense in the Linux program, whereas a lot of the stuff in the DOS one still makes me go "Huh?" Lets check out the differences:

  1. Firstly, getting the command line arguments of the Linux program is way easier than the DOS one. All the arguments are sitting on the stack when the program starts, so all we need to do is pop them off. The first value popped off is the number of arguments (called argc in C/C++), the second is the name of the program, and finally we get the actual command line arguments. Coolest of all, when we pop the command line argument off the stack, it actually puts the address of that string in EBX, so once again no segment/offset missions.
    This just took us an entire 3 instructions - compared to the 14 insane ones for the DOS program! No messing around with PSPs and stuff - simple, isn't it?
  2. NB: NASM doesn't have procedures like you may have used in TASM. That's because procedures don't really exist in assembly: everything is a label. So if you want to write a "procedure" in NASM, you don't use proc and endp, but instead just put a label (eg. filewrite:) at the beginning of the "procedure's" code. If you want to, you can put comments at the start and end of the code just to make it look a bit more like a procedure (like I did in the example).
  3. NB2: When you jump to a label with JMP or any of the jump instructions, you don't RET from it. Never! If you're lucky it won't explode on you, but it's definitely not right. The only time you RET is when you've called the "procedure" with CALL. Otherwise you're just going to have to jump around like a kangaroo weaving a spaghetti code masterpiece. (Note that this is applicable to any assembly, not just Linux or NASM).
  4. Next we create the file: notice the file permissions in Linux (you can find out more about them by reading the creat syscall's manpage – yes, it is spelled "creat"). Since we want to be smart with Linux, why not also include some error checking while we're at it? We can easily check if the creat syscall failed by checking the value it returned: if it's less than 0 then something broke, so skip the writing part and exit with the error code.
  5. Now we write 'Hello world!' to the file using the file descriptor (called file handle in DOS) returned by the creat syscall. Then we close it, and exit.
Not so hectic at all.

On the side: If you look at the DOS service functions (int 21h), you may notice that there are quite a few that have exactly the same names as their Unix/Linux syscall counterparts – even though DOS is quite unlike Unix and very much incompatible with it. For example: DOS 3Ch = CREAT, Unix 08h = creat and DOS 43h = CHMOD, Unix 0Fh = chmod. Mmm... so where did these DOS functions get their names? From Unix of course! What is really amusing is that Microsoft never bothered to spell "CREAT" right – they kept it exactly like Unix's "creat".

5. Compiling and Linking

To compile a program with NASM:

nasm -f elf program.asm
To link the object file produced by NASM into an executable:
ld -s -o program program.o
The -f elf option tells NASM to compile this in Linux ELF format. This option is necessary because NASM can compile many different formats (even DOS .COM files if you're so inclined).
The -s option for Ld tells it to strip all symbol information (which you don't need) from the output file. -o program specifies the name of the output executable file. If you leave it out it will always be a.out

Appendix A. References

Writing a useful program with NASM
The NASM documentation
Introduction to UNIX assembly programming
Linux Assembler Tutorial by Robin Miyagi
Section 2 of the manpages

asmtut/index.html0100644000102300017500000010155407460765636014256 0ustar dericklabusers

Linux Assembly Tutorial

Step-by-Step Guide

Written by: Derick Swanepoel (derick@maple.up.ac.za)
Version 1.0 - 2002-04-19, 01:50am

Download as zipfile

JMP Quickstart

Contents

1. Introduction
2. Why this Tutorial?
3. The Netwide Assembler (NASM)
3.1 A Note on Assemblers
3.2 Where do I get NASM?
4. Introduction to Linux Assembly
4.1 Main Differences Between DOS and Linux Assembly
4.2 The Parts of an Assembly Program
4.3 Linux System Calls
4.3.1 Reading the Manpages
4.4 "Hello World!" in Linux Assembly
4.5 Compiling and Linking
5. More Advanced Concepts
5.1 Command Line Arguments and the Stack
5.2 "Procedures" and Jumping
6. Conclusion

Appendix A. The terminal is your friend - how to use it
Appendix B. Installing NASM (and other stuff) on Linux
Appendix C. References

 

1. Introduction

This tutorial is an introduction to coding assembly in Linux. There are two "versions" to accommodate various people:

The assembler I'll be using is NASM (Netwide Assembler). Lots of the stuff in this tutorial came from other tuts and the NASM documentation – see the References section for more info.  

2. Why this Tutorial?

Mainly, the reason for this tutorial is to make assembly programming easier, better and more practical by doing it in Linux instead of DOS. Also, it may teach you a bit of Linux while you're at it (unless you're already at home with it).

Programming in assembly may seem quite masochistic (and writing entire programs in it simply ridiculous), especially in these days of super-optimizing compilers and visual development tools that do just about everything for you. However, there is an advantage in understanding more about the inner workings of your processor and kernel, and assembly is a good way of learning this. Sometimes assembly can be extremely useful for sticking inline in a C/C++ program. And if your program really has a "need for speed", you can tweak and optimize the assembly generated by the compiler (of course, you need to be pretty elite to produce better code than today's compilers.)

Since there was this notion that we were to be taught how to use Linux during COS284 (sort of as an aside), the idea was that we would code assembly in Linux. But not Linux assembly - DOS assembly, in a DOS emulator, with a DOS text editor. Of course, this entirely defeats the purpose, but maybe it was to be done this way mainly because there aren't so many Linux assembly tutorials and sample code as for DOS. Well, here is a tutorial that'll teach you the basics of Linux assembly.


3. The Netwide Assembler (NASM)

3.1 A Note on Assemblers

Linux will almost always be intalled with the default assemblers as and as86 available, and quite likely also gas. However, we will be using NASM, the Netwide Assembler. It uses the Intel syntax just like TASM, MASM, and other DOS assemblers, and the structure is also fairly similar. (Useless info: as and gas use the AT&T syntax, which is somewhat different – eg. all registers must be prefixed with a %, and the source operand comes before the destination. See the References for a link to a tut using as and AT&T syntax.)

NASM is cool because it's portable (there are Linux, Unix and DOS versions), it's free and it's powerful with lots of nice features. Trust me.

3.2 Where do I get NASM?

If you selected "Development Tools" when you installed Linux, chances are you already have NASM. It comes standard with most Linux distributions, so you don't need to download it. To check if you've got it, just ask Linux, "Where is NASM?" Here's how:

  1. Open a terminal. (For some basic Linux terminal skills, go to The terminal is your friend - how to use it)
  2. Type whereis nasm and press ENTER.

If you see a line that says something like nasm: /usr/bin/nasm then you're fine. If all you see is nasm: then you need to install NASM. Here are some instructions on how to install NASM (or anything else) on Linux.

If you feel like getting the latest and greatest version of NASM, visit their website www.cryogen.com/Nasm, or get it with FTP from our local Linux mirror ftp.kernel.za.org/pub/software/devel/nasm/binaries.


4. Introduction to Linux Assembly

4.1 Main Differences Between DOS and Linux Assembly

4.2 The Parts of an Assembly Program

An assembly program can be divided into three sections:

As you can see, so far things are still more or less DOSish. Next we'll look at system calls in more detail, and once that is done you'll be able to write your first Linux assembly program!

4.3 Linux System Calls

Linux system calls are called in exactly the same way as DOS system calls:

  1. You put the system call number in EAX (we're dealing with 32-bit registers here, remember)
  2. You set up the arguments to the system call in EBX, ECX, etc.
  3. You call the relevant interrupt (for DOS, 21h; for Linux, 80h)
  4. The result is usually returned in EAX
There are six registers that are used for the arguments that the system call takes. The first argument goes in EBX, the second in ECX, then EDX, ESI, EDI, and finally EBP, if there are so many. If there are more than six arguments, EBX must contain the memory location where the list of arguments is stored - but don't worry about this because it's unlikely that you'll use a syscall with more than six arguments. The wonderful thing about this scheme is that Linux uses it consistently – all system calls are designed this way, there are no confusing exceptions.

Some example code always helps:

	mov	eax,1       ; The exit syscall number
	mov	ebx,0       ; Have an exit code of 0
	int	80h         ; Interrupt 80h, the thing that pokes the kernel and says, "Yo, do this"

But how do you find out what these system calls are, and what they do, and what arguments they take? Firstly, all the syscalls are listed in /usr/include/asm/unistd.h, together with their numbers (the value to put in EAX before you call int 80h). However, for your convenience you can simply find them in this Linux System Call Table, together with some other useful information (eg. what arguments they take). Take a look at the list of syscalls – there are things like sys_write (4), sys_nice (34) and of course sys_exit (1). To find out just what these things do, you can look them up in the Linux manual pages (commonly called "the manpages"). That is what the next section is about.

4.3.1 Reading the Manpages

First, open a terminal (or switch to one of the 6 consoles with CTRL+ALT+F1 through F6 - to get back to graphical mode press CTRL+ALT+F7). Say now you want to know what the "write" syscall does. Type man 2 write and press ENTER. This will bring up the manual page on "write" from section 2 of the manpages.

Under the NAME section is the syscall's name and what it does – in this case:

write - write to a file descriptor
This is the syscall you use to write to, well, a file. But you also use it to print stuff on the screen. "Why the heck is that?" you ask. See, in Linux everything is a file. Things like the screen, mice, printers, etc. are special files called "device files", but you read and write to them just like you do to a text file. This actually makes sense, because reading/writing files is one of the simplest things to do in programming, so why not do everything in the same simple way - but I digress.

Next, under the SYNOPSIS section you see a fairly ugly line:

ssize_t write(int fd, const void *buf, size_t count);
OK, if you know C it won't be ugly, because this is just the C definition of the syscall. As you can see, it takes three arguments: the file descriptor, followed by the buffer, and then how many bytes to write, which should be however long the buffer is. (The DESCRIPTION section tells us what the arguments are for.) The file descriptor (fd) is an integer, the buffer (buf) is a pointer to a memory location (that's what the * means), so it's also an integer, and the bytes to write (count) is of type size_t, which is also an integer. This makes sense because we put values for these arguments in the registers EBX, ECX and EDX, which are all 32-bit integers. Finally, the write syscall returns a value in EAX: the number of bytes actually written. This can be used to verify if all went well. DESCRIPTION fdbufcount

Now we can finally write our first Linux assembly program!

4.4 "Hello World!" in Linux Assembly

Of course, the appropriate way to begin would be to print out "Hello world!" To print to the screen, we write to the special file called STDOUT (standard output), which is file descriptor 1. Here is the program in full:

section .data
	hello:     db 'Hello world!',10    ; 'Hello world!' plus a linefeed character
	helloLen:  equ $-hello             ; Length of the 'Hello world!' string
	                                   ; (I'll explain soon)

section .text
	global _start

_start:
	mov eax,4            ; The system call for write (sys_write)
	mov ebx,1            ; File descriptor 1 - standard output
	mov ecx,hello        ; Put the offset of hello in ecx
	mov edx,helloLen     ; helloLen is a constant, so we don't need to say
	                     ;  mov edx,[helloLen] to get it's actual value
	int 80h              ; Call the kernel

	mov eax,1            ; The system call for exit (sys_exit)
	mov ebx,0            ; Exit with return code of 0 (no error)
	int 80h

Copy this program into a text editor of your choice (I use vi or SciTE), and save it as hello.asm in your home directory (/home/yourname).

4.5 Compiling and Linking

  1. If you don't have a terminal or console open, open one now.
  2. Make sure you are in the same directory as where you saved hello.asm.
  3. To assemble the program, type
    nasm -f elf hello.asm
    If there are any errors, NASM will tell you on what line you did what wrong.
  4. Now type ld -s -o hello hello.o
    This will link the object file NASM produced into an executable file.
  5. Run your program by typing ./hello
    (To run programs/scripts in the current directory, you must always type ./ before the name, unless the current directory is in the path.)
You should see Hello world! printed to the screen. Congratulations! You have just written your first assembly program in Linux! Hello world!  

5. More Advanced Concepts

Before I go on, you're probably wondering what that equ $-hello thing is doing in our Hello World program (line 3). As you may remember, when you use equ to declare a variable (instead of db, for example), you are actually declaring a constant. Declaring the length of our string as a constant is sensible because it sure isn't going to change. But how does $-hello turn out to be the length of 'Hello world!' ? When NASM sees a '$' it replaces it with the assembly position at the beginning of that line. (That is also the position at the end of the previous line.) So subtracting the position of a variable from '$' will give us the number of bytes between the variable and '$'. If we want to declare a variable that contains the length of a string we've declared by saying hello: db 'Hello world!',10 then we just stick helloLen: equ $-hello on the next line. That will make helloLen equal to the number of bytes that hello takes up in memory, which in this case is 13 (the linefeed character also counts). Don't worry if this confuses you – just remember that it's a neat and easy way to declare the length of a string.

If you're more than just casually interested, I'd encourage you to check out the NASM documentation for more information on these things, and how to use some of the other neat features that I'm not going to mention in this tutorial.

5.1 Command Line Arguments and the Stack

Getting the command line arguments from a DOS program is not an enjoyable experience, because working with the PSP and having to worry about segments is simply a pain. In Linux things are much simpler: all arguments are available on the stack when the program starts, so to get them you just pop them off.

As an example, say you run a program called program and give it three arguments:

./program foo bar 42
The stack will then look as follows:
4
program
foo
bar
42
Number of arguments (argc), including the program name
Name of the program (argv[0])
Argument 1, the first real argument (argv[1])
Argument 2 (argv[2])
Argument 3 (argv[3]) (Note: this is the string "42", not the number 42)

Now lets write the program program that takes the three arguments:

section .text
	global _start

_start:
	pop	eax		; Get the number of arguments
	pop	ebx		; Get the program name
	pop	ebx		; Get the first actual argument ("foo")
	pop	ecx		; "bar"
	pop	edx		; "42"

	mov	eax,1
	mov	ebx,0
	int	80h		; Exit
After all that popping, EAX contains the number of arguments, EBX points to wherever "foo" is stored in memory, ECX points to "bar" and EDX to "42". This is obviously way more elegant and simple than in DOS. It took us just 5 lines to get the arguments and even how many there are, while in DOS it takes 14 rather complicated lines just to get one argument! Note that the 3rdpop overwrites the value we put in EBX with the 2ndpop (which was the program name). Unless you have a really good reason, you can usually chuck away the program name as we did here. way one rd pop nd pop

5.2 "Procedures" and Jumping

NB: NASM doesn't have procedure definitions like you may have used in TASM. That's because procedures don't really exist in assembly: everything is a label. So if you want to write a "procedure" in NASM, you don't use proc and endp, but instead just put a label (eg. fileWrite:) at the beginning of the "procedure's" code. If you want to, you can put comments at the start and end of the code just to make it look a bit more like a procedure. Here's an example in both Linux and DOS:
Linux DOS
; proc fileWrite - write a string to a file
fileWrite:
   mov eax,4               ; write system call
   mov ebx,[filedesc]      ; File descriptor
   mov ecx,stuffToWrite
   mov edx,[stuffLen]
   int 80h
   ret
; endp fileWrite

proc fileWrite
   mov ah,40h              ; write DOS service
   mov bx,[filehandle]     ; File handle
   mov cl,[stuffLen]
   mov dx,offset stuffToWrite
   int 21h
   ret
endp fileWrite

NB2: I assume that you're familiar with labels and jumping to them with instructions like JMP, JE or JGE. Now that you've seen that "procedures" are actually labels, there is one very important thing to remember: If you are planning to return from a procedure (with the RET instruction), don't jump to it! As in "never!" Doing that will cause a segmentation fault on Linux (which is OK – all your program does is terminate), but in DOS it may blow up in your face with various degrees of terribleness. The rule to remember is:

You may jump to labels, but you must call a procedure.

Calling a procedure is of course done with the CALL instruction. This makes life a bit difficult when you want to do things like "if-then-else". If you have a situation such as "if this happens, call procedure 1, else call procedure 2" there's only one thing to do: Jump around like a kangaroo weaving a spaghetti code masterpiece. Lets look at an example. First, here is some normal, sane code:

	if (AX == 'w') {
	   writeFile();
	} else {
	   doSomethingElse();
	}
This is how you would do it in assembly:
	cmp	AX,'w'		; Does AX contain 'w'?
	jne	skipWrite	; If not, skip writing by jumping to another label, and doSomethingElse there...
	call	writeFile	; ...else call the writeFile procedure...
	jmp	outOfThisMess	; ...and jump past all of this spaghetti

skipWrite:
	call	doSomethingElse
outOfThisMess:
	...			; The rest of the program goes on here
Note that this is applicable to any assembly, not just Linux or NASM.

5.3 A Program with Everything

Now we can finally take a look at a program that does something remotely useful, containing almost everything we've covered. In the Quickstart version of this tutorial, I have included a Linux and a DOS version of the program we wrote in Practical 3 (the one that writes 'Hello world!' to the file given as a command line argument). Check it out and see how much simpler and logical the Linux program is compared to the DOS one.

 

6. Conclusion

Well, that's about it for this tutorial. I hope this has been a suitable introduction to doing assembly programming in Linux. If you have any questions, suggestions or problems, feel free to e-mail me at derick@maple.up.ac.za. This is my first tutorial and I'm no assembly hacker either, so I welcome your comments.

Good luck and happy coding!


 

Appendix A. The terminal is your friend - how to use it

The terminal / console is an integral and very useful part of Linux. Linux has an excellent set of command line utilities and programs, and you can control the whole system without a GUI. Sometimes this is actually easier and faster. For programming in assembly you are obviously going to have to work in the terminal, and this part will show you how.

Before you start, keep in mind that Unix/Linux is case sensitive, so "Blah" is not the same as "blah" or "blaH".

It is often useful to have more than just one terminal open, for example one to compile your program in and another to read manpages with. Also, most window managers (KDE, Gnome, IceWM are window managers) allow you to work on multiple desktops. So when one desktop gets cluttered with windows, just go to another one and "start with a clean slate!" In KDE and Gnome you'll see four numbered little squares on the taskbar. Click on one and it takes you to that desktop. (You can have up to 10 desktops if you want.) I have on one rare occasion worked on 4 consoles and 3 desktops at the same time because of all the different stuff I was doing!  

Appendix B. Installing NASM (and other stuff) on Linux

In order to install programs on your Linux system, you must be root (administrator). You can decide whether you want to do this with the GUI utilities or in a terminal – I recommend you try both, for the added experience ;)

Using KDE / Gnome

If you're working in KDE / Gnome, installing things is fairly straightforward:

  1. If you are logged in as a normal user, log out and log in as root.
  2. Pop your Linux CD in your CD-ROM drive, and it should be automounted (NASM is on the 2nd CD). You can then use a file manager (Konqueror, Nautilus) to go to /mnt/cdrom where you should see the contents of the Linux CD. If there's nothing, go to the desktop, right-click on the CD-ROM icon and click "Mount".
  3. In /mnt/cdrom, go to RedHat, then RPMS. You should see a lot of files with the extension .RPM – look for nasm-0.98-8.i386.rpm.
  4. Click/double-click on it to open it with the package manager. From there it shouldn't be too much of a mission to install. Also install nasm-doc-0.98-8.i386.rpm, the documentation for NASM.

Using the Terminal

Installing stuff by means of a terminal isn't difficult either:

  1. If you weren't logged in as root, become root in the terminal by typing su (for "substitute user"). After entering your password, you will now be logged in on that terminal as root.
  2. Mount the CD-ROM by typing mount /dev/cdrom
  3. Change to the packages directory: cd /mnt/cdrom/RedHat/RPMS
  4. Install NASM with the RedHat Package Manager, by typing: rpm -i nasm-0.98-8.i386.rpm
    (Hint: use tab-completion!)
    Also install nasm-doc-0.98-8.i386.rpm, the documentation for NASM.
  5. If you su'd to become root, type exit to log out and stop being root.
If everything was successful, congratulations! You're well on your way to becoming an elite Linux user. If something broke, feel free to e-mail me and I'll do my best to help. Good luck, and happy hacking in Linux!  

Appendix C. References

Writing a useful program with NASM
The NASM documentation
Introduction to UNIX assembly programming
Linux Assembler Tutorial by Robin Miyagi
Section 2 of the manpages

asmtut/syscalls.html0100644000102300017500000023010207457741702014766 0ustar dericklabusers

(source)


Linux System Call Table

The following table lists the system calls for the Linux 2.2 kernel. It could also be thought of as an API for the interface between user space and kernel space. My motivation for making this table was to make programming in assembly language easier when using only system calls and not the C library (for more information on this topic, go to http://www.linuxassembly.org). On the left are the numbers of the system calls. This number will be put in register %eax. On the right of the table are the types of values to be put into the remaining registers before calling the software interrupt 'int 0x80'. After each syscall, an integer is returned in %eax.

For convenience, the kernel source file where each system call is located is linked to in the column labelled "Source". In order to use the hyperlinks, you must first copy this page to your own machine because the links take you directly to the source code on your system. You must have the kernel source installed (or linked from) under '/usr/src/linux' for this to work.

%eaxNameSource %ebx%ecx%edx%esx%edi
1sys_exitkernel/exit.c int----
2sys_forkarch/i386/kernel/process.c struct pt_regs----
3sys_readfs/read_write.c unsigned intchar *size_t--
4sys_writefs/read_write.c unsigned intconst char *size_t--
5sys_openfs/open.c const char *intint--
6sys_closefs/open.c unsigned int----
7sys_waitpidkernel/exit.c pid_tunsigned int *int--
8sys_creatfs/open.c const char *int---
9sys_linkfs/namei.c const char *const char *---
10sys_unlinkfs/namei.c const char *----
11sys_execvearch/i386/kernel/process.c struct pt_regs----
12sys_chdirfs/open.c const char *----
13sys_timekernel/time.c int *----
14sys_mknodfs/namei.c const char *intdev_t--
15sys_chmodfs/open.c const char *mode_t---
16sys_lchownfs/open.c const char *uid_tgid_t--
18sys_statfs/stat.c char *struct __old_kernel_stat *---
19sys_lseekfs/read_write.c unsigned intoff_tunsigned int--
20sys_getpidkernel/sched.c -----
21sys_mountfs/super.c char *char *char *--
22sys_oldumountfs/super.c char *----
23sys_setuidkernel/sys.c uid_t----
24sys_getuidkernel/sched.c -----
25sys_stimekernel/time.c int *----
26sys_ptracearch/i386/kernel/ptrace.c longlonglonglong-
27sys_alarmkernel/sched.c unsigned int----
28sys_fstatfs/stat.c unsigned intstruct __old_kernel_stat *---
29sys_pausearch/i386/kernel/sys_i386.c -----
30sys_utimefs/open.c char *struct utimbuf *---
33sys_accessfs/open.c const char *int---
34sys_nicekernel/sched.c int----
36sys_syncfs/buffer.c -----
37sys_killkernel/signal.c intint---
38sys_renamefs/namei.c const char *const char *---
39sys_mkdirfs/namei.c const char *int---
40sys_rmdirfs/namei.c const char *----
41sys_dupfs/fcntl.c unsigned int----
42sys_pipearch/i386/kernel/sys_i386.c unsigned long *----
43sys_timeskernel/sys.c struct tms *----
45sys_brkmm/mmap.c unsigned long----
46sys_setgidkernel/sys.c gid_t----
47sys_getgidkernel/sched.c -----
48sys_signalkernel/signal.c int__sighandler_t---
49sys_geteuidkernel/sched.c -----
50sys_getegidkernel/sched.c -----
51sys_acctkernel/acct.c const char *----
52sys_umountfs/super.c char *int---
54sys_ioctlfs/ioctl.c unsigned intunsigned intunsigned long--
55sys_fcntlfs/fcntl.c unsigned intunsigned intunsigned long--
57sys_setpgidkernel/sys.c pid_tpid_t---
59sys_oldunamearch/i386/kernel/sys_i386.c struct oldold_utsname *----
60sys_umaskkernel/sys.c int----
61sys_chrootfs/open.c const char *----
62sys_ustatfs/super.c dev_tstruct ustat *---
63sys_dup2fs/fcntl.c unsigned intunsigned int---
64sys_getppidkernel/sched.c -----
65sys_getpgrpkernel/sys.c -----
66sys_setsidkernel/sys.c -----
67sys_sigactionarch/i386/kernel/signal.c intconst struct old_sigaction *struct old_sigaction *--
68sys_sgetmaskkernel/signal.c -----
69sys_ssetmaskkernel/signal.c int----
70sys_setreuidkernel/sys.c uid_tuid_t---
71sys_setregidkernel/sys.c gid_tgid_t---
72sys_sigsuspendarch/i386/kernel/signal.c intintold_sigset_t--
73sys_sigpendingkernel/signal.c old_sigset_t *----
74sys_sethostnamekernel/sys.c char *int---
75sys_setrlimitkernel/sys.c unsigned intstruct rlimit *---
76sys_getrlimitkernel/sys.c unsigned intstruct rlimit *---
77sys_getrusagekernel/sys.c intstruct rusage *---
78sys_gettimeofdaykernel/time.c struct timeval *struct timezone *---
79sys_settimeofdaykernel/time.c struct timeval *struct timezone *---
80sys_getgroupskernel/sys.c intgid_t *---
81sys_setgroupskernel/sys.c intgid_t *---
82old_selectarch/i386/kernel/sys_i386.c struct sel_arg_struct *----
83sys_symlinkfs/namei.c const char *const char *---
84sys_lstatfs/stat.c char *struct __old_kernel_stat *---
85sys_readlinkfs/stat.c const char *char *int--
86sys_uselibfs/exec.c const char *----
87sys_swaponmm/swapfile.c const char *int---
88sys_rebootkernel/sys.c intintintvoid *-
89old_readdirfs/readdir.c unsigned intvoid *unsigned int--
90old_mmaparch/i386/kernel/sys_i386.c struct mmap_arg_struct *----
91sys_munmapmm/mmap.c unsigned longsize_t---
92sys_truncatefs/open.c const char *unsigned long---
93sys_ftruncatefs/open.c unsigned intunsigned long---
94sys_fchmodfs/open.c unsigned intmode_t---
95sys_fchownfs/open.c unsigned intuid_tgid_t--
96sys_getprioritykernel/sys.c intint---
97sys_setprioritykernel/sys.c intintint--
99sys_statfsfs/open.c const char *struct statfs *---
100sys_fstatfsfs/open.c unsigned intstruct statfs *---
101sys_iopermarch/i386/kernel/ioport.c unsigned longunsigned longint--
102sys_socketcallnet/socket.c intunsigned long *---
103sys_syslogkernel/printk.c intchar *int--
104sys_setitimerkernel/itimer.c intstruct itimerval *struct itimerval *--
105sys_getitimerkernel/itimer.c intstruct itimerval *---
106sys_newstatfs/stat.c char *struct stat *---
107sys_newlstatfs/stat.c char *struct stat *---
108sys_newfstatfs/stat.c unsigned intstruct stat *---
109sys_unamearch/i386/kernel/sys_i386.c struct old_utsname *----
110sys_ioplarch/i386/kernel/ioport.c unsigned long----
111sys_vhangupfs/open.c -----
112sys_idlearch/i386/kernel/process.c -----
113sys_vm86oldarch/i386/kernel/vm86.c unsigned longstruct vm86plus_struct *---
114sys_wait4kernel/exit.c pid_tunsigned long *int optionsstruct rusage *-
115sys_swapoffmm/swapfile.c const char *----
116sys_sysinfokernel/info.c struct sysinfo *----
117sys_ipc (*Note)arch/i386/kernel/sys_i386.c uintintintintvoid *
118sys_fsyncfs/buffer.c unsigned int----
119sys_sigreturnarch/i386/kernel/signal.c unsigned long----
120sys_clonearch/i386/kernel/process.c struct pt_regs----
121sys_setdomainnamekernel/sys.c char *int---
122sys_newunamekernel/sys.c struct new_utsname *----
123sys_modify_ldtarch/i386/kernel/ldt.c intvoid *unsigned long--
124sys_adjtimexkernel/time.c struct timex *----
125sys_mprotectmm/mprotect.c unsigned longsize_tunsigned long--
126sys_sigprocmaskkernel/signal.c intold_sigset_t *old_sigset_t *--
127sys_create_modulekernel/module.c const char *size_t---
128sys_init_modulekernel/module.c const char *struct module *---
129sys_delete_modulekernel/module.c const char *----
130sys_get_kernel_symskernel/module.c struct kernel_sym *----
131sys_quotactlfs/dquot.c intconst char *intcaddr_t-
132sys_getpgidkernel/sys.c pid_t----
133sys_fchdirfs/open.c unsigned int----
134sys_bdflushfs/buffer.c intlong---
135sys_sysfsfs/super.c intunsigned longunsigned long--
136sys_personalitykernel/exec_domain.c unsigned long----
138sys_setfsuidkernel/sys.c uid_t----
139sys_setfsgidkernel/sys.c gid_t----
140sys_llseekfs/read_write.c unsigned intunsigned longunsigned longloff_t *unsigned int
141sys_getdentsfs/readdir.c unsigned intvoid *unsigned int--
142sys_selectfs/select.c intfd_set *fd_set *fd_set *struct timeval *
143sys_flockfs/locks.c unsigned intunsigned int---
144sys_msyncmm/filemap.c unsigned longsize_tint--
145sys_readvfs/read_write.c unsigned longconst struct iovec *unsigned long--
146sys_writevfs/read_write.c unsigned longconst struct iovec *unsigned long--
147sys_getsidkernel/sys.c pid_t----
148sys_fdatasyncfs/buffer.c unsigned int----
149sys_sysctlkernel/sysctl.c struct __sysctl_args *----
150sys_mlockmm/mlock.c unsigned longsize_t---
151sys_munlockmm/mlock.c unsigned longsize_t---
152sys_mlockallmm/mlock.c int----
153sys_munlockallmm/mlock.c -----
154sys_sched_setparamkernel/sched.c pid_tstruct sched_param *---
155sys_sched_getparamkernel/sched.c pid_tstruct sched_param *---
156sys_sched_setschedulerkernel/sched.c pid_tintstruct sched_param *--
157sys_sched_getschedulerkernel/sched.c pid_t----
158sys_sched_yieldkernel/sched.c -----
159sys_sched_get_priority_maxkernel/sched.c int----
160sys_sched_get_priority_minkernel/sched.c int----
161sys_sched_rr_get_intervalkernel/sched.c pid_tstruct timespec *---
162sys_nanosleepkernel/sched.c struct timespec *struct timespec *---
163sys_mremapmm/mremap.c unsigned longunsigned longunsigned longunsigned long-
164sys_setresuidkernel/sys.c uid_tuid_tuid_t--
165sys_getresuidkernel/sys.c uid_t *uid_t *uid_t *--
166sys_vm86arch/i386/kernel/vm86.c struct vm86_struct *----
167sys_query_modulekernel/module.c const char *intchar *size_tsize_t *
168sys_pollfs/select.c struct pollfd *unsigned intlong--
169sys_nfsservctlfs/filesystems.c intvoid *void *--
170sys_setresgidkernel/sys.c gid_tgid_tgid_t--
171sys_getresgidkernel/sys.c gid_t *gid_t *gid_t *--
172sys_prctlkernel/sys.c intunsigned longunsigned longunsigned longunsigned long
173sys_rt_sigreturnarch/i386/kernel/signal.c unsigned long----
174sys_rt_sigactionkernel/signal.c intconst struct sigaction *struct sigaction *size_t-
175sys_rt_sigprocmaskkernel/signal.c intsigset_t *sigset_t *size_t-
176sys_rt_sigpendingkernel/signal.c sigset_t *size_t---
177sys_rt_sigtimedwaitkernel/signal.c const sigset_t *siginfo_t *const struct timespec *size_t-
178sys_rt_sigqueueinfokernel/signal.c intintsiginfo_t *--
179sys_rt_sigsuspendarch/i386/kernel/signal.c sigset_t *size_t---
180sys_preadfs/read_write.c unsigned intchar *size_tloff_t-
181sys_pwritefs/read_write.c unsigned intconst char *size_tloff_t-
182sys_chownfs/open.c const char *uid_tgid_t--
183sys_getcwdfs/dcache.c char *unsigned long---
184sys_capgetkernel/capability.c cap_user_header_tcap_user_data_t---
185sys_capsetkernel/capability.c cap_user_header_tconst cap_user_data_t---
186sys_sigaltstackarch/i386/kernel/signal.c const stack_t *stack_t *---
187sys_sendfilemm/filemap.c intintoff_t *size_t-
190sys_vforkarch/i386/kernel/process.c struct pt_regs----

Note for sys_ipc (117): this syscall takes six arguments, so it can't fit into the five registers %ebx - %edi; the last parameter (not shown) is of type 'long'. This syscall requires a special call method where a pointer is put in %ebx which points to an array containing the six arguments.

I will now explain exactly where in the kernel source that I got the information in the table above. I do this because 1) changes in the source are bound to happen, 2) you might be curious, or 3) I might've made an error.

System Call Numbers

For the numbers of the syscalls, look in arch/i386/kernel/entry.S for sys_call_table. The syscall numbers are offsets into that table. Several spots in the table are occupied by the syscall sys_ni_syscall. This is a placeholder that either replaces an obsolete syscall or reserves a spot for future syscalls.

Incidentally, the system calls are called from the function system_call in the same file; in particular, they are called with the assembly instruction 'call *SYMBOL_NAME(sys_call_table)(,%eax,4)'. The part '*SYMBOL_NAME(sys_call_table)' just gets replaced by a symbol name in sys_call_table. SYMBOL_NAME is a macro defined in include/linux/linkage.h, and it just replaces itself with its argument.

Typedefs

Here are the typedef declarations in the prototypes above:

atomic_t include/asm/atomic.h:
#ifdef __SMP__
typedef struct { volatile int counter; } atomic_t;
#else
typedef struct { int counter; } atomic_t;
#endif
caddr_t include/asm/posix_types.h:typedef char * __kernel_caddr_t;
include/linux/types.h:typedef __kernel_caddr_t caddr_t;
cap_user_header_t include/linux/capability.h:
typedef struct __user_cap_header_struct {
     __u32 version;
     int pid;
} *cap_user_header_t;
cap_user_data_t include/linux/capability.h:
typedef struct __user_cap_data_struct {
     __u32 effective;
     __u32 permitted;
     __u32 inheritable;
} *cap_user_data_t;
clock_t include/asm/posix_types.h:typedef long __kernel_clock_t;
include/linux/types.h:typedef __kernel_clock_t clock_t;
dev_t include/asm/posix_types.h:typedef unsigned short __kernel_dev_t;
include/linux/types.h:typedef __kernel_dev_t dev_t;
fdset include/linux/posix_types.h
#define __FD_SETSIZE 1024
#define __NFDBITS (8 * sizeof(unsigned long))
#define __FDSET_LONGS (__FD_SETSIZE/__NFDBITS)
(==> __FDSET_LONGS == 32)

typedef struct {
     unsigned long fds_bits [__FDSET_LONGS];
} __kernel_fd_set;
include/linux/types.h:typedef __kernel_fd_set fd_set;
gid_t include/asm/posix_types.h:typedef unsigned short __kernel_gid_t;
include/linux/types.h:typedef __kernel_gid_t gid_t;
__kernel_daddr_t include/asm/posix_types.h:typedef int __kernel_daddr_t;
__kernel_fsid_t include/asm/posix_types.h:
typedef struct {
     int __val[2];
} __kernel_fsid_t;

__kernel_ino_t include/asm/posix_types.h:typedef unsigned long __kernel_ino_t;
__kernel_size_t include/asm/posix_types.h:typedef unsigned int __kernel_size_t;
loff_t include/asm/posix_types.h:typedef long long __kernel_loff_t;
include/linux/types.h:typedef __kernel_loff_t loff_t;
mode_t include/asm/posix_types.h:typedef unsigned short __kernel_mode_t;
include/linux/types.h:typedef __kernel_mode_t mode_t;
off_t include/asm/posix_types.h:typedef long __kernel_off_t; include/linux/types.h:typedef __kernel_off_t off_t;
old_sigset_t include/asm/signal.h:typedef unsigned long old_sigset_t;
pid_t include/asm/posix_types.h:typedef int __kernel_pid_t;
include/linux/types.h:typedef __kernel_pid_t pid_t;
__sighandler_t include/asm/signal.h:typedef void (*__sighandler_t)(int);
siginfo_t include/asm/siginfo.h:
#define SI_MAX_SIZE 128
#define SI_PAD_SIZE ((SI_MAX_SIZE/sizeof(int)) - 3)
(==> SI_PAD_SIZE == 29)

typedef struct siginfo {
     int si_signo;
     int si_errno;
     int si_code;

     union {
          int _pad[SI_PAD_SIZE];

          /* kill() */
          struct {
               pid_t _pid; /* sender's pid */
               uid_t _uid; /* sender's uid */
          } _kill;

          /* POSIX.1b timers */
          struct {
               unsigned int _timer1;
               unsigned int _timer2;
          } _timer;

          /* POSIX.1b signals */
          struct {
               pid_t _pid; /* sender's pid */
               uid_t _uid; /* sender's uid */
               sigval_t _sigval;
          } _rt;

          /* SIGCHLD */
          struct {
               pid_t _pid; /* which child */
               uid_t _uid; /* sender's uid */
               int _status; /* exit code */
               clock_t _utime;
               clock_t _stime;
          } _sigchld;

          /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
          struct {
               void *_addr; /* faulting insn/memory ref. */
          } _sigfault;

          /* SIGPOLL */
          struct {
               int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
               int _fd;
          } _sigpoll;
     } _sifields;
} siginfo_t;
sigset_t include/asm/signal.h:typedef unsigned long sigset_t;
size_t include/asm/posix_types.h:typedef unsigned int __kernel_size_t;
include/linux/types.h:typedef __kernel_size_t size_t;
ssize_t include/asm/posix_types.h:typedef int __kernel_ssize_t;
include/linux/types.h:typedef __kernel_ssize_t ssize_t;
stack_t include/asm/signal.h:
typedef struct sigaltstack {
     void *ss_sp;
     int ss_flags;
     size_t ss_size;
} stack_t;
suseconds_t include/asm/posix_types.h:typedef long __kernel_suseconds_t;
include/linux/types.h:typedef __kernel_suseconds_t suseconds_t;
time_t include/asm/posix_types.h:typedef long __kernel_time_t; include/linux/types.h:typedef __kernel_time_t time_t;
uid_t include/asm/posix_types.h:typedef unsigned short __kernel_uid_t;
include/linux/types.h:typedef __kernel_uid_t uid_t;
uint include/linux/types.h:typedef unsigned int uint;
__u32 include/asm/types.h:typedef unsigned int __u32;

 

Struct Declarations

Here are the struct declarations for the table at the top:

exception_table_entry include/linux/module.h:
struct exception_table_entry {
     unsigned long insn, fixup;
};
iovec include/linux/uio.h:
struct iovec {
     void *iov_base;
     __kernel_size_t iov_len; };
itimerval include/linux/time.h:
struct itimerval {
     struct timeval it_interval; /* timer interval */
     struct timeval it_value; /* current value */
};
kernel_sym include/linux/module.h:
struct kernel_sym {
     unsigned long value;
     char name[60];
};
mmap_arg_struct arch/i386/kernel/sys_i386.c:
struct mmap_arg_struct {
     unsigned long addr;
     unsigned long len;
     unsigned long prot;
     unsigned long flags;
     unsigned long fd;
     unsigned long offset;
};
module include/linux/module.h:
struct module {
     unsigned long size_of_struct; /* sizeof(module) */
     struct module *next;
     const char *name;
     unsigned long size;
     union {
          atomic_t usecount;
          long pad;
     } uc;
     unsigned long flags; /* AUTOCLEAN et al */
     unsigned nsyms;
     unsigned ndeps;

     struct module_symbol *syms;
     struct module_ref *deps;
     struct module_ref *refs;
     int (*init)(void);
     void (*cleanup)(void);
     const struct exception_table_entry *ex_table_start;
     const struct exception_table_entry *ex_table_end;
/* Members past this point are extensions to the basic
module support and are optional. Use mod_opt_member()
to examine them. */
     const struct module_persist *persist_start;
     const struct module_persist *persist_end;
     int (*can_unload)(void);
};
module_persist include/linux/module.h:
struct module_persist; /* yes, it's empty */
module_ref include/linux/module.h:
struct module_ref {
     struct module *dep; /* "parent" pointer */
     struct module *ref; /* "child" pointer */
     struct module_ref *next_ref;
};
module_symbol include/linux/module.h:
struct module_symbol {
     unsigned long value;
     const char *name;
};
new_utsname include/linux/utsname.h:
struct new_utsname {
     char sysname[65];
     char nodename[65];
     char release[65];
     char version[65];
     char machine[65];
     char domainname[65];
};
__old_kernel_stat include/asm/stat.h:
struct __old_kernel_stat {
     unsigned short st_dev;
     unsigned short st_ino;
     unsigned short st_mode;
     unsigned short st_nlink;
     unsigned short st_uid;
     unsigned short st_gid;
     unsigned short st_rdev;
     unsigned long st_size;
     unsigned long st_atime;
     unsigned long st_mtime;
     unsigned long st_ctime;
};
oldold_utsname include/linux/utsname.h:
struct oldold_utsname {
     char sysname[9];
     char nodename[9];
     char release[9];
     char version[9];
     char machine[9];
};
old_sigaction include/asm/signal.h:
struct old_sigaction {
     __sighandler_t sa_handler;
     old_sigset_t sa_mask;
     unsigned long sa_flags;
     void (*sa_restorer)(void);
};
old_utsname include/linux/utsname.h:
struct old_utsname {
     char sysname[65];
     char nodename[65];
     char release[65];
     char version[65];
     char machine[65];
};
pollfd include/asm/poll.h:
struct pollfd {
     int fd;
     short events;
     short revents;
};
pt_regs include/asm/ptrace.h:
struct pt_regs {
     long ebx;
     long ecx;
     long edx;
     long esi;
     long edi;
     long ebp;
     long eax;
     int xds;
     int xes;
     long orig_eax;
     long eip;
     int xcs;
     long eflags;
     long esp;
     int xss;
};
revectored_struct include/asm/vm86.h:
struct revectored_struct {
     unsigned long __map[8];
};
rlimit include/linux/resource.h:
struct rlimit {
     long rlim_cur;
     long rlim_max;
};
rusage include/linux/resource.h:
struct rusage {
     struct timeval ru_utime; /* user time used */
     struct timeval ru_stime; /* system time used */
     long ru_maxrss; /* maximum resident set size */
     long ru_ixrss; /* integral shared memory size */
     long ru_idrss; /* integral unshared data size */
     long ru_isrss; /* integral unshared stack size */
     long ru_minflt; /* page reclaims */
     long ru_majflt; /* page faults */
     long ru_nswap; /* swaps */
     long ru_inblock; /* block input operations */
     long ru_oublock; /* block output operations */
     long ru_msgsnd; /* messages sent */
     long ru_msgrcv; /* messages received */
     long ru_nsignals; /* signals received */
     long ru_nvcsw; /* voluntary context switches */
     long ru_nivcsw; /* involuntary '' */
};
sched_param include/linux/sched.h:
struct sched_param {
     int sched_priority;
};
sel_arg_struct arch/i386/kernel/sys_i386.c:
struct sel_arg_struct {
     unsigned long n;
     fd_set *inp, *outp, *exp;
     struct timeval *tvp;
};
sigaction include/asm/signal.h:
struct sigaction {
     __sighandler_t sa_handler;
     unsigned long sa_flags;
     void (*sa_restorer)(void);
     sigset_t sa_mask; /* mask last for extensibility */
};
stat include/asm/stat.h:
struct stat {
     unsigned short st_dev;
     unsigned short __pad1;
     unsigned long st_ino;
     unsigned short st_mode;
     unsigned short st_nlink;
     unsigned short st_uid;
     unsigned short st_gid;
     unsigned short st_rdev;
     unsigned short __pad2;
     unsigned long st_size;
     unsigned long st_blksize;
     unsigned long st_blocks;
     unsigned long st_atime;
     unsigned long __unused1;
     unsigned long st_mtime;
     unsigned long __unused2;
     unsigned long st_ctime;
     unsigned long __unused3;
     unsigned long __unused4;
     unsigned long __unused5;
statfs include/asm/statfs.h:
struct statfs {
     long f_type;
     long f_bsize;
     long f_blocks;
     long f_bfree;
     long f_bavail;
     long f_files;
     long f_ffree;
     __kernel_fsid_t f_fsid;
     long f_namelen;
     long f_spare[6];
};
__sysctl_args include/linux/sysctl.h
struct __sysctl_args {
     int *name;
     int nlen;
     void *oldval;
     size_t *oldlenp;
     void *newval;
     size_t newlen;
     unsigned long __unused[4];
};
sysinfo include/linux/kernel.h:
struct sysinfo {
     long uptime; /* Seconds since boot */
     unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
     unsigned long totalram; /* Total usable main memory size */
     unsigned long freeram; /* Available memory size */
     unsigned long sharedram; /* Amount of shared memory */
     unsigned long bufferram; /* Memory used by buffers */
     unsigned long totalswap; /* Total swap space size */
     unsigned long freeswap; /* swap space still available */
     unsigned short procs; /* Number of current processes */
     char _f[22]; /* Pads structure to 64 bytes */
};
timex include/linux/timex.h:
struct timex {
     unsigned int modes; /* mode selector */
     long offset; /* time offset (usec) */
     long freq; /* frequency offset (scaled ppm) */
     long maxerror; /* maximum error (usec) */
     long esterror; /* estimated error (usec) */
     int status; /* clock command/status */
     long constant; /* pll time constant */
     long precision; /* clock precision (usec) (read only) */
     long tolerance; /* clock frequency tolerance (ppm)
      * (read only)
      */
     struct timeval time; /* (read only) */
     long tick; /* (modified) usecs between clock ticks */
     long ppsfreq; /* pps frequency (scaled ppm) (ro) */
     long jitter; /* pps jitter (us) (ro) */
     int shift; /* interval duration (s) (shift) (ro) */
     long stabil; /* pps stability (scaled ppm) (ro) */
     long jitcnt; /* jitter limit exceeded (ro) */
     long calcnt; /* calibration intervals (ro) */
     long errcnt; /* calibration errors (ro) */
     long stbcnt; /* stability limit exceeded (ro) */

     int :32; int :32; int :32; int :32;
     int :32; int :32; int :32; int :32;
     int :32; int :32; int :32; int :32;
};
timespec include/linux/time.h:
struct timespec {
     time_t tv_sec; /* seconds */
     long tv_nsec; /* nanoseconds */
};
timeval include/linux/time.h:
struct timeval {
     time_t tv_sec; /* seconds */
     suseconds_t tv_usec; /* microseconds */
};
timezone include/linux/time.h:
struct timezone {
     int tz_minuteswest; /* minutes west of Greenwich */
     int tz_dsttime; /* type of dst correction */
};
tms include/linux/times.h
struct tms {
     clock_t tms_utime;
     clock_t tms_stime;
     clock_t tms_cutime;
     clock_t tms_cstime;
};
ustat include/linux/types.h:
struct ustat {
     __kernel_daddr_t f_tfree;
     __kernel_ino_t f_tinode;
     char f_fname[6];
     char f_fpack[6];
};
utimbuf include/linux/utime.h:
struct utimbuf {
     time_t actime;
     time_t modtime;
};
vm86plus_info_struct include/asm/vm86.h:
struct vm86plus_info_struct {
     unsigned long force_return_for_pic:1;
     unsigned long vm86dbg_active:1;
     unsigned long vm86dbg_TFpendig:1;
     unsigned long unused:28;
     unsigned long is_vm86pus:1;
     unsigned char vm86dbg_intxxtab[32];
};
vm86plus_struct include/asm/vm86.h:
struct vm86plus_struct {
     struct vm86_regs regs;
     unsigned long flags;
     unsigned long screen_bitmap;
     unsigned long cpu_type;
     struct revectored_struct int_revectored;
     struct revectored_struct int21_revectored;
     struct vm86plus_info_struct vm86plus;
};
vm86_regs include/asm/vm86.h:
struct vm86_regs {
/* normal regs, with special meaning for the segment descriptors.. */
     long ebx;
     long ecx;
     long edx;
     long esi;
     long edi;
     long ebp;
     long eax;
     long __null_ds;
     long __null_es;
     long __null_fs;
     long __null_gs;
     long orig_eax;
     long eip;
     unsigned short cs, __csh;
     long eflags;
     long esp;
     unsigned short ss, __ssh;
/* these are specific to v86 mode: */
     unsigned short es, __esh;
     unsigned short ds, __dsh;
     unsigned short fs, __fsh;
     unsigned short gs, __gsh;
};
vm86_struct include/asm/vm86.h:
struct vm86_struct {
     struct vm86_regs regs;
     unsigned long flags;
     unsigned long screen_bitmap;
     unsigned long cpu_type;
     struct revectored_struct int_revectored;
     struct revectored_struct int21_revectored;
};