CMPSC 311, Introduction to Systems Programming

Course Intro



Reading
Extra Reading



Let's start with three questions
What is Systems Programming?
What do System Programs provide?
What are the issues facing System Programmers?
Abstraction and Implementation
Modern systems are built by connecting components.
Some examples of system components used by a large application program



This course is intended to provide background information and programming experience to prepare you for more detailed and broader studies of the internals of Operating Systems, and the principles and practice of Software Engineering.

In this course,
We will assume that you know
We will not assume that you know anything about
By the end of the course, if successful, you will know a lot about
System programming is about tool building, so you need to understand
Some of the programming tools we will discuss are command-line shells and text editors.  You might suffer withdrawal symptoms from going without your fancy graphics display and mouse.



System programming requires you to be aware of the resources that your program uses.

Exercise
void foo(void) { int bar; foo(); }
int main(void) { foo(); return 0; }

Exercise
Exercise Exercise Exercise, to test your tolerance for ambiguity
Exercise
  1. ignore the problem and keep going.
  2. check the input as you go, report an error if you find one, and keep going.
  3. check the input as you go, open a dialog box with the user if you find an error, and refuse to continue until you get valid data.
  4. check the input as you go, report an error if you find one, and then quit.
  5. work as 2, 3 or 4, but also send an email message to yourself so you know what kind of mistakes the users are making; this should help you improve the program and documentation.
Exercise Exercises



Some initial concepts and vocabulary
Example
If you want to see some real code, take a look at these from OpenSolaris.
Infrastructure
Exercise



Everyone's first example.  (% is the command-line prompt)

% cd /tmp

% vi hello.c

#include <stdio.h>

int main(void)
{
  printf("hello, world\n");

  return 0;
}

% cc -o hello hello.c

% hello
hello, world

% ./hello
hello, world

What did the compiler actually do?  It created an executable file.  On Solaris, ...

% ls -l hello*
-rwx------   1 dheller  fcse        6988 Aug 21 15:39 hello
-rw-------   1 dheller  fcse          68 Aug 21 15:38 hello.c

% file hello*
hello:          ELF 32-bit MSB executable SPARC32PLUS Version 1, V8+ Required, dynamically linked, not stripped
hello.c:        c program text

(ELF = Executable and Linking Format)

What is in the executable file?

% od -x hello
0000000 7f45 4c46 0102 0100 0000 0000 0000 0000
0000020 0002 0012 0000 0001 0001 0670 0000 0034
0000040 0000 1764 0000 0100 0034 0020 0005 0028
0000060 0019 0018 0000 0006 0000 0034 0001 0034
... further output omitted

% od -c hello
0000000 177   E   L   F 001 002 001  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000020  \0 002  \0 022  \0  \0  \0 001  \0 001 006   p  \0  \0  \0   4
0000040  \0  \0 027   d  \0  \0 001  \0  \0   4  \0      \0 005  \0   (
0000060  \0 031  \0 030  \0  \0  \0 006  \0  \0  \0   4  \0 001  \0   4

... further output omitted

The executable file contains machine instructions and organizational information.

% elfdump hello
ELF Header
  ei_magic:   { 0x7f, E, L, F }
  ei_class:   ELFCLASS32          ei_data:      ELFDATA2MSB
  e_machine:  EM_SPARC32PLUS      e_version:    EV_CURRENT
  e_type:     ET_EXEC
  e_flags:    [ EF_SPARC_32PLUS ]
  e_entry:               0x10670  e_ehsize:     52  e_shstrndx:   24
  e_shoff:                0x1764  e_shentsize:  40  e_shnum:      25
  e_phoff:                  0x34  e_phentsize:  32  e_phnum:       5

... further output omitted

What happens when the program runs?  On Solaris, ...

% hello
hello, world

% sotruss hello
hello           ->       libc.so.1:*atexit(0xff3c0220, 0x20c00, 0x0)
hello           ->       libc.so.1:*atexit(0x10be8, 0xff0ecbc0, 0xa7bf4)
hello           ->       libc.so.1:*printf(0x10bf8, 0x0, 0x0)
hello, world
hello           ->       libc.so.1:*exit(0x0, 0xffbffa14, 0xffbffa1c)

% apptrace hello
-> hello    -> libc.so.1:int atexit(int (*)() = 0xff3c0220)
<- hello    -> libc.so.1:atexit()
-> hello    -> libc.so.1:int atexit(int (*)() = 0x10be0)
<- hello    -> libc.so.1:atexit()
-> hello    -> libc.so.1:int printf(const char * = 0x10bf0 "hello, world
", void * = 0xff3f0f58, ...)
hello, world
<- hello    -> libc.so.1:printf() = 0xd
-> hello    -> libc.so.1:exit(0x1, 0xffbffab4, 0xffbffabc) ** NR

% truss hello
execve("hello", 0xFFBFFB0C, 0xFFBFFB14)  argc = 1
resolvepath("/usr/lib/ld.so.1", "/lib/ld.so.1", 1023) = 12
getcwd("/tmp", 1017)                            = 0
resolvepath("/tmp/hello", "/tmp/hello", 1023)   = 10
stat("/tmp/hello", 0xFFBFF8E8)                  = 0
open("/var/ld/ld.config", O_RDONLY)             Err#2 ENOENT
stat("/lib/libc.so.1", 0xFFBFF408)              = 0
resolvepath("/lib/libc.so.1", "/lib/libc.so.1", 1023) = 14
open("/lib/libc.so.1", O_RDONLY)                = 3
mmap(0x00010000, 8192, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_ALIGN, 3, 0) = 0xFF3A0000
mmap(0x00010000, 991232, PROT_NONE, MAP_PRIVATE|MAP_NORESERVE|MAP_ANON|MAP_ALIGN, -1, 0) = 0xFF280000
mmap(0xFF280000, 881573, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_TEXT, 3, 0) = 0xFF280000
mmap(0xFF368000, 29469, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_INITDATA, 3, 884736) = 0xFF368000
mmap(0xFF370000, 2592, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_ANON, -1, 0) = 0xFF370000
munmap(0xFF358000, 65536)                       = 0
memcntl(0xFF280000, 139692, MC_ADVISE, MADV_WILLNEED, 0, 0) = 0
close(3)                                        = 0
munmap(0xFF3A0000, 8192)                        = 0
mmap(0x00010000, 24576, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANON|MAP_ALIGN, -1, 0) = 0xFF3A0000
getcontext(0xFFBFF5E0)
getrlimit(RLIMIT_STACK, 0xFFBFF5C0)             = 0
getpid()                                        = 891 [890]
setustack(0xFF3A2088)
ioctl(1, TCGETA, 0xFFBFEC4C)                    = 0
fstat64(1, 0xFFBFEB68)                          = 0
stat("/platform/SUNW,Sun-Blade-1500/lib/libc_psr.so.1", 0xFFBFE768) = 0
resolvepath("/platform/SUNW,Sun-Blade-1500/lib/libc_psr.so.1", "/platform/sun4u-us3/lib/libc_psr.so.1", 1023) = 37
open("/platform/SUNW,Sun-Blade-1500/lib/libc_psr.so.1", O_RDONLY) = 3
mmap(0x00010000, 8192, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_ALIGN, 3, 0) = 0xFF390000
close(3)                                        = 0
hello, world
write(1, " h e l l o ,   w o r l d".., 13)      = 13
_exit(1)

What happens when the program runs?  On Linux, ...

% hello
hello, world

% ltrace hello
_start(0x7fbffff9ed, 0x325c811966, 0x325c80b4e0, 0x3d52455355006f6c, 0xfefefefefefefeff <unfinished ...>
__libc_start_main(0x4004a8, 1, 0x7fbffff7d8, 0x4004c0, 0x400520 <unfinished ...>
printf("hello, world\n"hello, world
)                                                            = 13
+++ exited (status 13) +++

% strace hello
execve("./hello", ["hello"], [/* 30 vars */]) = 0
uname({sys="Linux", node="bogus.cse.psu.edu", ...}) = 0
brk(0)                                  = 0x501000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2a95556000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=133511, ...}) = 0
mmap(NULL, 133511, PROT_READ, MAP_PRIVATE, 3, 0) = 0x2a95557000
close(3)                                = 0
open("/lib64/tls/libc.so.6", O_RDONLY)  = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\240\304\241\\2\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1622288, ...}) = 0
mmap(0x325ca00000, 2314184, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x325ca00000
mprotect(0x325cb2c000, 1085384, PROT_NONE) = 0
mmap(0x325cc2c000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x12c000) = 0x325cc2c000
mmap(0x325cc31000, 16328, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x325cc31000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2a95578000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2a95579000
mprotect(0x325cc2c000, 12288, PROT_READ) = 0
mprotect(0x325c914000, 4096, PROT_READ) = 0
arch_prctl(ARCH_SET_FS, 0x2a95578b00)   = 0
munmap(0x2a95557000, 133511)            = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 4), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2a95557000
write(1, "hello, world\n", 13hello, world
)          = 13
exit_group(13)                          = ?

What happens when the program runs?  On Mac OS X, ...

% hello
hello, world



Common Unix utilities and commands [exercise - what's the difference?]
Summary of tools mentioned here

tool
Solaris
Linux
Mac OS X
guess the type of a file
file
file
file
inspect a file, bytewise
od
od
hexdump
od
hexdump
inspect an executable file elfdump
objdump
otool
trace system calls
apptrace
sotruss
truss
ltrace
strace





We used some terms without adequate definition or examples.
Some definitions from the Posix Standard, 2008 edition

These are not really intended for beginners; they are too formal, and too broad, allowing for one specification to cover many implementations.  We added some comments [in brackets].  Some of this won't make sense until we get through the first few weeks of the course.

POSIX.1-2008 is simultaneously IEEE Std 1003.1™-2008 and The Open Group Technical Standard Base Specifications, Issue 7.  More about that later.



Although we won't discuss hand-held devices in this course, here's a quick overview of the Android software stack:
This clearly illustrates the idea of layered interfaces to the system hardware.  Linux manages devices, memory and processes.  The virtual machine supports Java programs.  The Java libraries support telephony, video, speech, graphics, network connectivity, user interfaces, etc.

The source code is available at http://source.android.com/ .



Last revised, 7 Jan. 2013