Skip to main content

4 posts tagged with "Systems Programming"

View All Tags

Writing Portable C Code: Preprocessor Directives, Data Types, and GNU Autotools

· 45 min read
Pranav Ram Joshi
Software Engineer — Systems & Networks

Preamble

Writing a portable C program turns out to be more of a nightmare than imagined. C is notorious for being platform dependent, yet most of the software that runs across wildly different systems is written in this language. The secret lies in understanding what varies between platforms — data type widths, byte ordering, memory alignment, available system calls and library functions — and using the right tools to handle those differences at build time. In this post, we'll walk through the C compilation pipeline, explore how preprocessor directives enable conditional compilation, examine data type portability pitfalls like endianness and struct padding, and introduce GNU Autotools as a build system for portable projects. This is the third in a three-part series. The first post covers UNIX terminal devices, and the second explains how the shell executes programs.

How the Shell Executes Programs: Fork, Exec, and Environment Variables

· 12 min read
Pranav Ram Joshi
Software Engineer — Systems & Networks

Preamble

A shell process is a command-line interpreter — the program that reads your input, locates the right program or builtin command, and orchestrates its execution. Whether you use Bourne Shell, Bash, Korn Shell, or another flavor, the underlying mechanics are remarkably similar: the shell forks a child process, the child replaces its image with the target program via exec, and the parent waits for completion. In this post, we'll trace that fork-exec-wait cycle step by step, explore how environment variables are passed to programs, and look at the shell's capabilities as an interpreter — including loops, conditionals, and history expansion. This is the second in a three-part series. The first post covers UNIX terminal devices and line discipline, and the third explores writing portable C code.

How UNIX Terminal Devices Work: TTY, Pseudo-Terminals, and Line Discipline

· 13 min read
Pranav Ram Joshi
Software Engineer — Systems & Networks

Preamble

When you open a terminal, you are greeted with a prompt and the system expects your input. But have you ever wondered what sort of device the terminal really is? A terminal is more than just a window for typing commands — it is a character special device managed by the kernel, with a layered architecture involving device drivers, line discipline modules, and pseudo-terminal pairs. In this post, we'll explore the internals of the UNIX terminal device: how tty and pty devices work, what terminal line discipline does, and how the kernel mediates between the user and the shell process. This is the first in a three-part series. The second post covers how the shell process executes programs, and the third explores writing portable C code.

Process Memory Layout on macOS ARM64: Address Spaces, Mach-O Segments, and Debugging with LLDB

· 37 min read
Pranav Ram Joshi
Software Engineer — Systems & Networks

Tools for Inspecting Process Memory and Object Files

Before we even step into the world of virtual memory and process address spaces, let's first learn of some tools which might come in handy when dealing with source programs (we'll describe them in lengths later):

  1. Object File Inspection. This can be done through various tools such as otool, objdump, and llvm-objdump.
  2. Debugger. Tools such as gdb and lldb can be helpful when inspecting how the program executes.
  3. Virtual Memory Information. Sometimes, we need to see how a process has arranged its virtual memory space. Tools such as vmmap, leaks, and pmap (also potentially strace) can be used for this purpose.

Other tools can come handy frequently as well. For instance, if we want to list the "files" currently owned by the process, lsof provides useful information.