Add examples for different utilities

This commit is contained in:
2026-02-24 13:46:16 +01:00
parent bacba9e8c8
commit 04c7146e84
5 changed files with 213 additions and 8 deletions

View File

@@ -0,0 +1,107 @@
#!/bin/bash
set -e
# Colours
BOLD='\033[1m'
CYAN='\033[1;36m'
GREEN='\033[1;32m'
YELLOW='\033[1;33m'
RESET='\033[0m'
header() { echo -e "\n${CYAN}══════════════════════════════════════════${RESET}"; \
echo -e "${BOLD} $1${RESET}"; \
echo -e "${CYAN}══════════════════════════════════════════${RESET}"; }
run() { echo -e "${YELLOW}\$ $*${RESET}"; eval "$@"; }
# ── 0. Clean up any previous artefacts ────────────────────────────────────────
header "0. Cleaning previous build artefacts"
rm -f *.o *.a *.so app
# ── 1. Compile to object files ────────────────────────────────────────────────
header "1. Compile source files to object files"
run g++ -std=c++17 -c math_lib.cpp -o math_lib.o
run g++ -std=c++17 -c main.cpp -o main.o
# ── 2. Create a static archive ────────────────────────────────────────────────
header "2. Pack into a static library (archive)"
run ar rcs libmath.a math_lib.o
echo -e "${GREEN}Created libmath.a${RESET}"
# ── 3. Create a shared library (with an embedded RPATH for ldd / chrpath) ─────
header "3. Build a shared library"
run g++ -std=c++17 -fPIC -c math_lib.cpp -o math_lib_pic.o
run g++ -shared math_lib_pic.o -o libmath.so
echo -e "${GREEN}Created libmath.so${RESET}"
# ── 4. Link the final executable (dynamic, rpath set to current dir) ──────────
header "4. Link the executable against the shared library"
run g++ main.o -L. -lmath -Wl,-rpath,"\$(pwd)" -o app
echo -e "${GREEN}Created app${RESET}"
# ══════════════════════════════════════════════════════════════════════════════
# DEBUG COMMANDS
# ══════════════════════════════════════════════════════════════════════════════
# ── 5. nm — inspect symbols ───────────────────────────────────────────────────
header "5a. nm -C -g libmath.a (demangled global symbols in the archive)"
run nm -C -g libmath.a
header "5b. nm -u main.o (undefined / unresolved symbols in main.o)"
run nm -u main.o
# ── 6. objdump — disassembly ──────────────────────────────────────────────────
header "6. objdump -d math_lib.o (disassembly of the library object)"
# Show only the first ~40 lines so the output stays readable
run "objdump -d math_lib.o | head -60"
# ── 7. readelf — ELF symbol table ────────────────────────────────────────────
header "7. readelf -s math_lib.o (full ELF symbol table)"
run readelf -s math_lib.o
# ── 8. Linker verbose — trace linker decisions ────────────────────────────────
header "8. g++ -Wl,--verbose (trace linker decisions, filtered to 'attempt')"
# Build a fresh app with --verbose so we can grep the attempt lines
run "g++ main.o -L. -lmath -Wl,--verbose -o app_verbose 2>&1 | grep attempt || true"
rm -f app_verbose
# ── 9. ld --trace ─────────────────────────────────────────────────────────────
header "9. ld --trace (every file the linker considers for math_lib.o)"
# We feed just the object file; ld will error because main() isn't provided,
# but --trace already prints all the files it opens before that.
echo -e "${YELLOW}\$ ld --trace math_lib.o (errors below are expected — main is absent)${RESET}"
ld --trace math_lib.o 2>&1 || true
# ── 10. ldd — shared library dependencies ─────────────────────────────────────
header "10. ldd ./app (runtime shared-library dependencies)"
run ldd ./app
# ── 11. chrpath — inspect / show embedded RPATH ──────────────────────────────
header "11. chrpath -l ./app (embedded RPATH recorded in the ELF header)"
if command -v chrpath &>/dev/null; then
run chrpath -l ./app
else
echo "(chrpath not installed — falling back to readelf)"
run "readelf -d ./app | grep -E 'RPATH|RUNPATH'"
fi
# ── 12. c++filt — demangle a mangled symbol ───────────────────────────────────
header "12. c++filt — demangle mangled symbol names"
# Show raw mangled names from the archive first so the demangling is tangible
echo -e "${YELLOW}Raw (mangled) global symbols in libmath.a:${RESET}"
nm -g libmath.a | grep " T " | awk '{print $NF}'
echo ""
echo -e "${YELLOW}Demangled with c++filt:${RESET}"
nm -g libmath.a | grep " T " | awk '{print $NF}' | c++filt
echo ""
echo -e "${YELLOW}Specific example from the lesson:${RESET}"
run "c++filt _ZN4Math4sqrtEd"
# ── 13. Run the program ───────────────────────────────────────────────────────
header "13. Run ./app"
run ./app
echo -e "\n${GREEN}${BOLD}Done.${RESET}"

View File

@@ -0,0 +1,27 @@
#include "math_lib.hpp"
#include <iostream>
int main() {
// --- Free functions ---
std::cout << "=== Free functions ===\n";
std::cout << "Math::sqrt(2.0) = " << Math::sqrt(2.0) << "\n";
std::cout << "Math::square(5.0) = " << Math::square(5.0) << "\n";
std::cout << "Math::cube(3.0) = " << Math::cube(3.0) << "\n";
// --- Vector2D ---
std::cout << "\n=== Vector2D ===\n";
Math::Vector2D v1(3.0, 4.0);
Math::Vector2D v2(1.0, 2.0);
std::cout << "v1.length() = " << v1.length() << "\n";
Math::Vector2D sum = v1.add(v2);
std::cout << "v1.add(v2) = (" << sum.x << ", " << sum.y << ")\n";
Math::Vector2D scaled = v1.scale(2.0);
std::cout << "v1.scale(2.0) = (" << scaled.x << ", " << scaled.y << ")\n";
std::cout << "v1.dot(v2) = " << v1.dot(v2) << "\n";
return 0;
}

View File

@@ -0,0 +1,40 @@
#include "math_lib.hpp"
#include <cmath>
namespace Math {
// --- Free functions ---
double sqrt(double x) {
return std::sqrt(x);
}
double square(double x) {
return x * x;
}
double cube(double x) {
return x * x * x;
}
// --- Vector2D ---
Vector2D::Vector2D(double x, double y) : x(x), y(y) {}
double Vector2D::length() const {
return std::sqrt(x * x + y * y);
}
Vector2D Vector2D::add(const Vector2D& other) const {
return Vector2D(x + other.x, y + other.y);
}
Vector2D Vector2D::scale(double factor) const {
return Vector2D(x * factor, y * factor);
}
double Vector2D::dot(const Vector2D& other) const {
return x * other.x + y * other.y;
}
} // namespace Math

View File

@@ -0,0 +1,26 @@
#pragma once
namespace Math {
// Free functions — each becomes a mangled symbol, e.g.
// Math::sqrt(double) → _ZN4Math4sqrtEd
// Math::square(double) → _ZN4Math6squareEd
// Math::cube(double) → _ZN4Math4cubeEd
double sqrt(double x);
double square(double x);
double cube(double x);
// Class — member functions add even richer mangling
class Vector2D {
public:
double x, y;
Vector2D(double x, double y);
double length() const;
Vector2D add(const Vector2D& other) const;
Vector2D scale(double factor) const;
double dot(const Vector2D& other) const;
};
} // namespace Math

View File

@@ -239,21 +239,26 @@ g++ main.cpp wrapper.cpp -lsqlite3 -o app
```bash
# Inspect symbols
nm -C -g lib.a # demangled, global symbols only
nm -u main.o # undefined (unresolved) symbols
objdump -d my.o # disassembly
readelf -s my.o # ELF symbol table
nm -C -g libmath.a # demangled, global symbols only
nm -u main.o # undefined (unresolved) symbols
objdump -d math_lib.o # disassembly
readelf -s math_lib.o # ELF symbol table
# Trace linker decisions
g++ main.o -lmylib -Wl,--verbose 2>&1 | grep "attempt"
ld --trace my.o # shows each file the linker considers
g++ main.o -L. -lmath -Wl,--verbose 2>&1 | grep "attempt"
ld --trace math_lib.o # shows each file the linker considers
# Check shared lib deps
ldd ./app
chrpath -l ./app # show embedded RPATH
chrpath -l ./app # show embedded RPATH
# fallback if chrpath is not installed:
readelf -d ./app | grep -E 'RPATH|RUNPATH'
# Demangle a mangled symbol
c++filt _ZN4Math4sqrtEd # → Math::sqrt(double)
c++filt _ZN4Math4sqrtEd # → Math::sqrt(double)
# Pipe nm output through c++filt to demangle all symbols at once
nm -g libmath.a | grep " T " | awk '{print $NF}' | c++filt
```
**Useful flags:**