{"id":15762097,"url":"https://github.com/harshkapadia2/compilation-examples","last_synced_at":"2026-06-23T20:31:14.304Z","repository":{"id":257325971,"uuid":"857930616","full_name":"HarshKapadia2/compilation-examples","owner":"HarshKapadia2","description":"Examples to illustrate Preprocessing, Compilation, Assembling and Linking.","archived":false,"fork":false,"pushed_at":"2024-10-02T22:57:47.000Z","size":434,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-10-11T11:27:35.415Z","etag":null,"topics":["assembling","c","compilation","linking","preprocessing"],"latest_commit_sha":null,"homepage":"","language":"SWIG","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/HarshKapadia2.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-16T01:02:57.000Z","updated_at":"2024-10-02T22:57:50.000Z","dependencies_parsed_at":"2024-09-16T02:34:59.790Z","dependency_job_id":"91171be7-3017-450a-94d7-a33b4bf488f2","html_url":"https://github.com/HarshKapadia2/compilation-examples","commit_stats":{"total_commits":24,"total_committers":1,"mean_commits":24.0,"dds":0.0,"last_synced_commit":"e31a5dfd01ac3123ba9fa8a842e31ffb2012fd13"},"previous_names":["harshkapadia2/compilation-examples"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/HarshKapadia2/compilation-examples","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HarshKapadia2%2Fcompilation-examples","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HarshKapadia2%2Fcompilation-examples/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HarshKapadia2%2Fcompilation-examples/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HarshKapadia2%2Fcompilation-examples/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/HarshKapadia2","download_url":"https://codeload.github.com/HarshKapadia2/compilation-examples/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HarshKapadia2%2Fcompilation-examples/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34706579,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-23T02:00:07.161Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["assembling","c","compilation","linking","preprocessing"],"created_at":"2024-10-04T11:06:45.157Z","updated_at":"2026-06-23T20:31:14.283Z","avatar_url":"https://github.com/HarshKapadia2.png","language":"SWIG","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Compilation Examples\n\n## Table of Contents\n\n-\t[Introduction](#introduction)\n-\t[Preprocessing](#preprocessing)\n\t-\t[Commands](#commands)\n-\t[Compilation](#compilation)\n\t-\t[Commands](#commands-1)\n-\t[Assembling](#assembling)\n\t-\t[Commands](#commands-2)\n\t-\t[Examining Object Files](#examining-object-files)\n-\t[Linking](#linking)\n\t-\t[Commands](#commands-3)\n\t-\t[Examining Executable Files](#examining-executable-files)\n\t-\t[Static and Dynamic Linking](#static-and-dynamic-linking)\n-\t[Resources](#resources)\n\n## Introduction\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"compilation-steps.png\" alt=\"The high level view of the compilation and loading steps of a program.\" loading=\"lazy\" /\u003e\n\t\u003cbr /\u003e\n    \u003csub\u003e\n        Image source: \u003ca href=\"https://www.tenouk.com/ModuleW.html\" target=\"_blank\" rel=\"noreferrer\"\u003eCompiler, Assembler, Linker and Loader: A Brief Story\u003c/a\u003e\n    \u003c/sub\u003e\n\u003c/p\u003e\n\nExamples to illustrate all the basic steps of compilation\n\n-\tPreprocessing\n-\tCompilation\n-\tAssembling\n-\tLinking\n\nCreated for [talks.harshkapadia.me/elf](https://talks.harshkapadia.me/elf).\n\n**NOTE**: Starter files are [`main.c`](main.c) and [`main.h`](main.h).\n\n## Preprocessing\n\nThe preprocessor substitutes macros, includes and conditional compilation\ninstructions with code.\n\n### Commands\n\n-\tNormal preprocessing\n\n\t```shell\n\t$ gcc -E main.c \u003e main.i\n\t```\n\n\tOutput: [`main.i`](main.i)\n\n-\tPreprocessing without standard includes\n\n\t```shell\n\t$ gcc -E -nostdinc main.c \u003e main-nostdinc.i 2\u003e\u00261\n\t```\n\n\tOutput: [`main-nostdinc.i`](main-nostdinc.i)\n\n## Compilation\n\nProcesses source code to convert it to Assembly that the Assembler can\nunderstand.\n\nIf dealing with GCC, then using the command below directly on the source code or\non the preprocessed code yields the same output.\n\n### Commands\n\n```shell\n$ gcc -S main.c\n```\n\nOutput: [`main.s`](main.s)\n\nEven if the preprocessed file generated in the Prepreocessing step\n([`main.i`](main.i)) is used, the same output as the above command can be\nexpected. This can be verified:\n\n-\tAfter running the above command, run\n\n\t```shell\n\t$ gcc -S main.i -o main-preproc.s\n\t```\n\n\tOutput: [`main-preproc.s`](main-preproc.s)\n\n-\tNow, to verify the differences between the output files `main.s` and\n\t`main-preproc.s`:\n\n\t```shell\n\t$ diff -s main.s main-preproc.s\n\tFiles main.s and main-preproc.s are identical\n\t```\n\n## Assembling\n\nGenerates machine code from Assembly and stores it in an object file.\n\nMachine code is a sequence of numbers that the CPU can understand and carry out\nactions based on.\n\n### Commands\n\n```shell\n$ gcc -c main.c\n```\n\nOutput: [`main.o`](main.o)\n\nThe same output can be generated through the following commands:\n\n-\tUsing GCC with the `main.s` file generated in the previous step\n\n\t```shell\n\t$ gcc -c main.s -o main-s.o\n\t```\n\n\tOutput: [`main-s.o`](main-s.o)\n\n-\tUsing the assembler `as` (GNU Assembler)\n\n\t```shell\n\t$ as main.s -o main-as.o\n\t```\n\n\tOutput: [`main-as.o`](main-as.o)\n\n-\tComparing the output of the three object files\n\n\t```shell\n\t$ diff -s main.o main-s.o\n\tFiles main.o and main-s.o are identical\n\n\t$ diff -s main-s.o main-as.o\n\tFiles main-s.o and main-as.o are identical\n\n\t# If main.o and main-s.o, and main-s.o and main-as.o are identical, then\n\t# main.o and main-as.o are also identical.\n\t```\n\n### Examining Object Files\n\nObject (`*.o`) files can be examined using\n[parse-elf](https://github.com/HarshKapadia2/parse-elf), `readelf`, `objdump`,\n`file`, etc.\n\nEg:\n\n```shell\n$ file main.o\nmain.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped\n```\n\nEg:\n\n```shell\n$ readelf --all main.o \u003e main-o-readelf.txt\n```\n\nOutput: [`main-o-readelf.txt`](main-o-readelf.txt)\n\nThe utility `objdump` can be used to disassemble the object file to view how the\nmachine code translates back to Asssembly.\n\n```shell\n$ objdump -d main.o\n\nmain.o:     file format elf64-x86-64\n\n\nDisassembly of section .text:\n\n0000000000000000 \u003cmain\u003e:\n   0:   f3 0f 1e fa             endbr64\n   4:   55                      push   %rbp\n   5:   48 89 e5                mov    %rsp,%rbp\n   8:   48 8b 05 00 00 00 00    mov    0x0(%rip),%rax        # f \u003cmain+0xf\u003e\n   f:   48 89 c7                mov    %rax,%rdi\n  12:   e8 00 00 00 00          call   17 \u003cmain+0x17\u003e\n  17:   48 8d 05 00 00 00 00    lea    0x0(%rip),%rax        # 1e \u003cmain+0x1e\u003e\n  1e:   48 89 c7                mov    %rax,%rdi\n  21:   e8 00 00 00 00          call   26 \u003cmain+0x26\u003e\n  26:   b8 00 00 00 00          mov    $0x0,%eax\n  2b:   5d                      pop    %rbp\n  2c:   c3                      ret\n```\n\nAs a side note, the machine code instructions consist of an Opcode and\nOperand(s). For example, `55` in the above disassembly output is an opcode for\nthe mnemonic `PUSH` in Assembly, which pushes a register's value onto the stack.\nAn opcode is an operation that the CPU can understand and execute. What an\nopcode represents is dependent on the Instruction Set Architecture (ISA) of the\nprocessor and is usually very well documented. (Eg: Vol. 2A of the [Intel 64 and IA-32 Architectures Software Developer Manuals](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html))\n\n[More information on opcodes, mnemonics, machine code, etc.](https://stackoverflow.com/questions/17638888/difference-between-opcode-byte-code-mnemonics-machine-code-and-assembly)\n\n## Linking\n\nThis is the last step in compilation that takes contents from several object\nfiles and/or libraries and combines them into one executable. References to\nextenal symbols are resolved.\n\n### Commands\n\n```shell\n$ gcc main.c\n```\n\nOutput: [`a.out`](a.out)\n\nThe default file name for the executable `a.out` is an abbreviation for\n'assembler output'.\n\nRunning the output file\n\n```shell\n$ ./a.out\nThis is the 'GLOBAL_VAR'.\n69\n```\n\nThe output file is an executable ELF file.\n\n```shell\n$ file a.out\na.out: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=d3f6d6241d69c2e0de9d136fb09190d9175f5171, for GNU/Linux 3.2.0, not stripped\n```\n\nGNU's Linker (`ld`) can also be used to link files.\n\n```shell\nld -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/Scrt1.o /usr/lib/x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/11/crtbeginS.o -lc main.o /usr/lib/gcc/x86_64-linux-gnu/11/crtendS.o /usr/lib/x86_64-linux-gnu/crtn.o -o a-ld.out\n```\n\nOutput: [`a-ld.out`](a-ld.out)\n\nAll the extra files apart from `main.o` in the `ld` command are to set up the\n`_start`, 'init' and 'fini' symbols and functions, which bootstrap the program\nby helping set up important registers for the program.\n\n[More information on the `crtxxx.o` files.](https://dev.gentoo.org/%7Evapier/crt.txt) (The letters `crt` are an abbreviation for 'C RunTime'.)\n\nRunning the output file\n\n```shell\n$ ./a-ld.out\nThis is the 'GLOBAL_VAR'.\n69\n```\n\n### Examining Executable Files\n\nExecutable files are ELF files that can be examined similar to Object files, as\nshown above in the ['Examining Object Files' section](#examining-object-files).\n\n```shell\n$ file a.out\na.out: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=c070be8a9201dd54b100277176bed8c1b6d68ffe, for GNU/Linux 3.2.0, not stripped\n```\n\nIn the ['Examining Object Files' section](#examining-object-files) above, the\n`main.o` file was disassembled. Let us check if disassembling the fully compiled\nexecutable `a.out` yields a different disassembled `main` function.\n\n```shell\n$ objdump -d a.out\n# ...\n\n0000000000001149 \u003cmain\u003e:\n    1149:       f3 0f 1e fa             endbr64\n    114d:       55                      push   %rbp\n    114e:       48 89 e5                mov    %rsp,%rbp\n    1151:       48 8b 05 b8 2e 00 00    mov    0x2eb8(%rip),%rax        # 4010 \u003cGLOBAL_VAR\u003e\n    1158:       48 89 c7                mov    %rax,%rdi\n    115b:       e8 f0 fe ff ff          call   1050 \u003cputs@plt\u003e\n    1160:       48 8d 05 b7 0e 00 00    lea    0xeb7(%rip),%rax        # 201e \u003c_IO_stdin_used+0x1e\u003e\n    1167:       48 89 c7                mov    %rax,%rdi\n    116a:       e8 e1 fe ff ff          call   1050 \u003cputs@plt\u003e\n    116f:       b8 00 00 00 00          mov    $0x0,%eax\n    1174:       5d                      pop    %rbp\n    1175:       c3                      ret\n\n# ...\n```\n\nThe opcodes in the instructions are unchanged, but there is a difference between\nthe addresses in the operands. This fully compiled version knows the location\n(address) of the library functions and variables required to run the program,\nunlike the disassembled output of the object file `main.o`.\n\nSome of the changes:\n\n```shell\n# main.o\n           8:   48 8b 05 00 00 00 00    mov    0x0(%rip),%rax        # f \u003cmain+0xf\u003e\n# a.out\n    1151:       48 8b 05 b8 2e 00 00    mov    0x2eb8(%rip),%rax        # 4010 \u003cGLOBAL_VAR\u003e\n\n# ----------------\n\n# main.o\n          12:   e8 00 00 00 00          call   17 \u003cmain+0x17\u003e\n# a.out\n    115b:       e8 f0 fe ff ff          call   1050 \u003cputs@plt\u003e\n```\n\n### Static and Dynamic Linking\n\nStatic linking includes library functions and variables into the main\nexecutable, thus making the executable independent of any runtime dependepcies,\nbut increasing the size of the executable.\n\nA dynamically linked execuatble includes references to functions and variables\nthat are resolved at runtime or load time. This reduces the executable's size\nand makes it easy to update the library without updating the executable, but\nmakes the executable vulnerable to breaking library changes and buggy library\nupdates.\n\nGenerating statically and dynamically linked binaries/executables\n```shell\n# Generating a statically linked executable\n$ gcc -static main.c -o a-static.out\n\n# Generating a dynamically linked executable (this is the default)\n$ gcc main.c     # Output file is 'a.out'\n```\n\nChecking the `file` command outputs\n\n```shell\n# Note 'statically linked' in the output\n$ file a-static.out\na-static.out: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=7d33ef89855ee508d79b4293e3489c860910abad, for GNU/Linux 3.2.0, not stripped\n\n# Note 'dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2' in the output\n$ file a.out\na.out: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=c070be8a9201dd54b100277176bed8c1b6d68ffe, for GNU/Linux 3.2.0, not stripped\n```\n\nChecking the `ldd` command output to check for dynamic library dependencies\n\n```shell\n# Statically linked binary does not have any dynamic dependencies\n$ ldd a-static.out\n        not a dynamic executable\n\n# Dynamically linked binary has dynamic libraries that it depends on\n$ ldd a.out\n        linux-vdso.so.1 (0x00007ffe79d1f000)\n        libc.so.6 =\u003e /lib/x86_64-linux-gnu/libc.so.6 (0x00007bcd55000000)\n        /lib64/ld-linux-x86-64.so.2 (0x00007bcd553ba000)\n```\n\nChecking the size of the two binaries\n\n```shell\n# Large size of the static binary!\n$ size a-static.out\n   text    data     bss     dec     hex filename\n 781885   23240   23016  828141   ca2ed a-static.out\n\n# Dynamically linked binary is smaller in size than the statically linked binary\n$ size a.out\n   text    data     bss     dec     hex filename\n   1430     608       8    2046     7fe a.out\n```\n\nDynamic linking can be of two types:\n-\tLoad-time Dynamic Linking\n\t-\tShared libraries and symbols are resolved by the Loader when the program\n\t\tis loaded into memory to be executed.\n-\tRun-time Dynamic Linking\n\t-\tReferences to functions and variables are left unresolved.\n\t-\tWhen a function or variable is referenced, an exception is raised, which\n\t\tis when the required entity is loaded and resolved.\n\n## Resources\n\n-\tGeneral\n\t-\t[Compiler, Assembler, Linker and Loader: A Brief Story](https://www.tenouk.com/ModuleW.html)\n\t-\t[How does the compilation/linking process work?](https://stackoverflow.com/questions/6264249/how-does-the-compilation-linking-process-work)\n\t-\t[Compiler, Linker, Assembler, and Loader](https://www.baeldung.com/cs/compiler-linker-assembler-loaderhttps://www.baeldung.com/cs/compiler-linker-assembler-loader)\n\t-\t[Running gcc's steps manually, compiling, assembling, linking](https://stackoverflow.com/questions/8527743/running-gccs-steps-manually-compiling-assembling-linking)\n-\tPreprocessing\n\t-\t[Running gcc's steps manually, compiling, assembling, linking](https://stackoverflow.com/questions/8527743/running-gccs-steps-manually-compiling-assembling-linking)\n\t-\t[How to view C preprocessor output?](https://stackoverflow.com/questions/3742822/how-to-view-c-preprocessor-output)\n\t-\t[[Interpreting] Preprocessor Output](https://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html)\n-\tAssemling\n\t-\t[Running gcc's steps manually, compiling, assembling, linking](https://stackoverflow.com/questions/8527743/running-gccs-steps-manually-compiling-assembling-linking)\n\t-\t[Difference between: Opcode, byte code, mnemonics, machine code and assembly](https://stackoverflow.com/questions/17638888/difference-between-opcode-byte-code-mnemonics-machine-code-and-assembly)\n \t-\t[Decoding x86 instructions with help of octal digits](https://www.youtube.com/watch?v=hN7mJ4nXC7M)\n\t-\t[Intel 64 and IA-32 Architectures Software Developer Manuals](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html)\n\t-\t[x86 and amd64 instruction reference](https://www.felixcloutier.com/x86)\n\t-\t[X86 Opcode and Instruction Reference](https://ref.x86asm.net)\n-\tLinking\n\t-\t[Running gcc's steps manually, compiling, assembling, linking](https://stackoverflow.com/questions/8527743/running-gccs-steps-manually-compiling-assembling-linking)\n \t-\t[Why does the order in which libraries are linked sometimes cause errors in GCC?](https://stackoverflow.com/questions/45135/why-does-the-order-in-which-libraries-are-linked-sometimes-cause-errors-in-gcc)\n\t-\t[How to link a gas assembly program that uses the C standard library with ld without using gcc?](https://stackoverflow.com/questions/3577922/how-to-link-a-gas-assembly-program-that-uses-the-c-standard-library-with-ld-with)\n\t-\t[More information on the `crtxxx.o` files.](https://dev.gentoo.org/%7Evapier/crt.txt)\n\t-\t[How to write and execute PURE machine code manually without containers like EXE or ELF?](https://stackoverflow.com/a/58489219/11958552)\n\t-\t[How does a linker know what all libraries to link?](https://stackoverflow.com/questions/9248533/how-does-a-linker-know-what-all-libraries-to-link)\n\t-\t[What do 'statically linked' and 'dynamically linked' mean?](https://stackoverflow.com/questions/311882/what-do-statically-linked-and-dynamically-linked-mean)\n \t-\tShared objects and `ldd` output\n  \t\t-\t[Where do executables look for shared objects at runtime?](https://unix.stackexchange.com/questions/22926/where-do-executables-look-for-shared-objects-at-runtime)\n    \t\t-\t[How Do so (Shared Object) Filenames Work?](https://www.baeldung.com/linux/shared-object-filenames)\n    \t\t-\t[Where is linux-vdso.so.1 present on the file system](https://stackoverflow.com/questions/58657036/where-is-linux-vdso-so-1-present-on-the-file-system)\n      \t\t-\t[What is /lib64/ld-linux-x86-64.so.2 and why can it be used to execute file?](https://unix.stackexchange.com/questions/400621/what-is-lib64-ld-linux-x86-64-so-2-and-why-can-it-be-used-to-execute-file)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fharshkapadia2%2Fcompilation-examples","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fharshkapadia2%2Fcompilation-examples","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fharshkapadia2%2Fcompilation-examples/lists"}