Skip to content
UnderDunn Courses

From Executable to Process

How Programs WorkLesson 1 of 745 minutesLab included

People use the word program for source code, an executable file, and a running process. Conversation usually survives this. Investigation does better when we are precise.

  • Source code describes behavior in a language such as C.
  • An executable file stores information and machine code in a format Linux knows how to load.
  • A process is one running instance with an identity, memory, execution state, and operating-system resources.

The executable is a file. It can sit on disk for years without doing anything. A process exists only while that program is running.

This distinction matters because a vulnerability may belong to instructions stored in an executable, but the evidence of its behavior appears in a process: memory changes, a crash, a file operation, or an unexpected system call.

Knowledge check

Question 1 of 2

Which item has a process ID and its own running state?

We will use sleep, a small utility that waits for a specified amount of time. Find the executable selected by your shell:

Terminal window
command -v sleep

On Ubuntu, the result will normally be /usr/bin/sleep. command -v asks the shell which command it would run for that name. This is better evidence than assuming every Linux installation stores a tool in the same place.

Store the result in a shell variable so later commands use the exact path you found:

Terminal window
sleep_path="$(command -v sleep)"
printf '%s\n' "$sleep_path"

Inspect the file:

Terminal window
file "$sleep_path"
stat "$sleep_path"

file should identify an ELF executable or shared object for your machine’s architecture. stat reports filesystem evidence such as size, ownership, permissions, and timestamps. At this point we have inspected a file; no sleep process was required.

Run sleep for two minutes and place it in the background:

Terminal window
sleep 120 &

The ampersand tells the shell not to wait for this command to finish before returning the prompt. The shell will print a job number and a process ID, commonly shortened to PID.

The shell also stores the PID of the most recently started background process in $!. Save it immediately:

Terminal window
sleep_pid=$!
printf 'PID: %s\n' "$sleep_pid"

A variable beginning with $ is expanded by the shell before the command runs. Quoting "$sleep_pid" preserves it as one argument and is a good habit even though a PID contains no spaces.

Inspect the process:

Terminal window
ps -p "$sleep_pid" -o pid,ppid,stat,comm,args

The headings mean:

Field What it tells us
PID The identity Linux assigned this process
PPID The process ID of its parent, normally your shell here
STAT A compact description of its current process state
COMMAND or COMM The short command name
COMMAND or ARGS The command and arguments used to start it

Your PID and parent PID will differ from anyone else’s. That difference is expected evidence, not a failure to match the screenshot that does not exist.

What happened between the command and the process?

Section titled “What happened between the command and the process?”

The complete startup path contains details we will uncover throughout the module. A useful first model is:

  1. The shell interpreted the command line and found the sleep executable.
  2. The shell asked the Linux kernel to create and start a process.
  3. Linux inspected the executable format.
  4. The loader mapped the required code and data into the new process’s virtual address space.
  5. Linux prepared the arguments and initial execution state.
  6. The processor began executing at the program’s designated entry point.

“Linux ran the file” is convenient shorthand, but it hides every interesting question. Which parts were mapped? Where did execution begin? How did the argument 120 reach the program? Those questions are the rest of this module.

Linux exposes information about running processes through /proc. Each process receives a directory named with its PID.

List the process directory:

Terminal window
ls -ld "/proc/$sleep_pid"

Now inspect the exe entry:

Terminal window
ls -l "/proc/$sleep_pid/exe"
readlink "/proc/$sleep_pid/exe"

exe is a symbolic link associated with the executable loaded for that process. readlink prints its target. The result should lead back to the same executable identified by command -v sleep, although one path may use a symbolic link or equivalent canonical location.

This gives us an evidence chain:

command name → executable path → PID → /proc/PID/exe → executable path

Start a second instance:

Terminal window
sleep 120 &
second_pid=$!
printf 'First PID: %s\nSecond PID: %s\n' "$sleep_pid" "$second_pid"

Inspect them together:

Terminal window
ps -p "$sleep_pid,$second_pid" -o pid,ppid,stat,comm,args

Both processes came from the same executable and received the same argument. They still have different PIDs. Each process also has its own /proc directory and runtime state.

Use readlink on both:

Terminal window
readlink "/proc/$sleep_pid/exe"
readlink "/proc/$second_pid/exe"

The targets should agree even though the PIDs do not. This is the difference between shared origin and separate running instances.

Knowledge check

Question 1 of 2

What does /proc/1234/exe represent when process 1234 exists?

Do not leave the two processes around and hope they eventually become someone else’s problem. Ask them to terminate:

Terminal window
kill "$sleep_pid" "$second_pid"
wait "$sleep_pid" "$second_pid"

kill sends a termination signal by default. wait asks the shell to collect the final status of its background children. You may see a short Terminated message; that describes the expected result of our cleanup.

Confirm that neither process remains:

Terminal window
ps -p "$sleep_pid,$second_pid" -o pid,stat,comm,args

Only the headings should remain. Their /proc directories should also be gone because /proc reflects processes that currently exist.

Add a short table to your research notebook:

Question Evidence
Which executable did the shell select? command -v output
What kind of file was it? Relevant file output
Which PIDs were created? Saved PIDs and ps output
What executable did each process use? Both readlink results
What disappeared after cleanup? Final ps result and /proc observation

Then explain, in your own words, why deleting a process and deleting an executable file are not the same operation.

You can now move deliberately between an executable on disk and a process created from it. You can identify the executable selected by the shell, record a process identity, inspect Linux’s live process view, and support the claim that several processes share one executable without confusing them for one running object.

Next, Reading an ELF File will open the executable itself and ask what Linux found inside that made loading possible.