Master the fundamental concepts of c programming deep dive through this focused micro-challenge.
After gcc -g file.c -o file, your C source lives as machine code in ELF sections. nm lists symbols: T for text (functions), D for initialized data, B for zero-initialized BSS, U for imports the linker must resolve. Static functions show up as lowercase t, hidden from other translation units.
bashLoading…
nm answers "is helper_function defined and how big is it?"objdump -d disassembles .text so you see call targets and prologuesobjdump -t dumps the full symbol table with VMA addressesThis is what engineers reach for when the linker reports duplicate symbols or when you need to verify the optimizer kept a function.
For this exercise, you will compile a program with globals, statics, and multiple functions, then inspect it with nm and objdump. This task asks you to map C declarations to section placement, because malware analysis, kernel debugging, and "undefined reference" hunts all start at this symbol table.
Keep the relevant man page, ABI doc, or Rust reference chapter open while you work. When your output disagrees with the reference implementation on the same machine, the mismatch is usually an alignment rule, an off-by-one terminator, or a register slot you misread in GDB.
nm lists an object file's symbols, and the letter next to each one tells you where it lives. Where a variable lands is decided entirely by its declaration: initialized or not, static or not, and whether it is really const. Write the classifier. Read file-scope C declarations (one per line) and print what nm -S would report for the object file, plus the section totals.
One declaration per line. Blank lines and // comment lines are skipped. Supported forms:
cLoading…
char (1 byte), short (2), int (4), long (8), float (4), double (8), or void (only behind * or for functions). unsigned/signed alone means int. A pointer is 8 bytes.[N] has N elements (1..100000). [] takes its size from the initializer: string length + 1 for char arrays, otherwise the element count.UL allowed), 'c' (\0, \n escapes), a "string", &name, or { e1, e2, ... } of those..text (T). A prototype, or an extern declaration without an initializer, is undefined (U) unless the same name is defined elsewhere in the input, before or after.const applies to the object itself: const int, char *const p, and arrays of const elements. const char *p is not: it is a writable pointer.&name): .data.rel.ro (D; the loader must patch it). Other top-level const objects: .rodata (R), even when zero or uninitialized..data (D) if there is an initializer and any part of it is non-zero, or .bss (B) if it is all zero or missing.static makes the letter lowercase (t r d b)..rodata.str1.1, and identical literals are stored once. A string that initializes a char array is not a literal: it is copied into the array.cLoading…
line N: error: redefinition of NAME (defining a name twice);line N: cannot parse: TEXT (anything outside the forms above, a void object, [] without an initializer, or a string longer than its array).Input:
cLoading…
Output:
cLoading…
clang -c for x86-64 Linux followed by nm -S.extern declaration with a later definition of the same name.Hidden tests cover zero-valued initializers of every kind, const zero and uninitialized const objects, .data.rel.ro, merged string literals, &name initializers, redefinitions, prototypes followed by definitions, and unsupported declarations.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it works