Build arcana
A set of arcana about build tools, linkers, programming languages etc which are probably only useful to me
- LD_DEBUG spits out debug information about linkers
- cmake –trace to trace the evaluation of a cmake file
- Use LD_PRELOAD + RTLD_NEXT in order to “intercept” function calls
- #include_next to include the next header file match. Similarly RTLD_NEXT
- RTLD_LOCAL to restrict symbol leak
- Linker version map
- Linker symbol map
- patchelf to directly modify attributes of an ELF
- ELF can be marked as NODELETE to not be deleted on NODELETE
- dl_close won’t unload a libary if it has any symbols marked as STB_GNU_UNIQUE (‘u’ in nm) or have any thread-local destructors registered
- sudo apt install package:arch to install package for specific architecture
- rpath and runpaths are attributes inside ELF which dictate where it’ll search for dynamic libraries
- dl_open can be used to implement loadable plugins
- procFS (mounted at /proc/pid) has info on command used to launch process, env, virtual memory maps, mount points, fds, files
- You can use stat on a process fd (
stat /proc/pid/fd/4
) - gdb -p pid to attach to a running process
- lldb – to forward args. Similarly gdb –args
- “directories” command in gdb can help set source path
- git checkout TAG
- cmake libs often parse the verbose output of a compiler to find dependencies
- LD_LIBRARY_PATH to add to the linker search path
- cargo thinks any directory inside “CARGO_HOME” is immutable. So it won’t detect changes if any dependencies are in there
- cargo build script for linker arguments, bindgen, etc
- abseil is a useful lib for env, multithreading, etc
- apt directories are seemingly wasting space by having an extra gzip header at the end
- meson runs serial tests after parallel
- git reflog when you mess things up
- meson test -C build_dir test_name
- dlsym to get a symbol from a handle obtained from dl_open
- cmake -D CMAKE_FIND_DEBUG_MODE to see where cmake is searching
- QEMU -g to start a gdb server & start debugging code running inside QEMU
- dlsym can be used to resolve circular dependencies
- push macro and pop macro preprocessor primitives to not pollute the namespace
__attribute__
to attach attributes to symbols- weak symbols
- fmap a function with multiple arguments then applying it to an applicative is a common pattern (f
<$>
m1<*>
m2<*>
m3) - Useful MMAP flags (MAP_PRIVATE to get a private copy, MAP_FIXED for fixed address space mapping)
- madvise syscall to pin pages, change policy to huge pages, other usage policies for kernel to optimize, poisoning
- mbind to bind to a NUMA node
- lspci to list PCI devices
- If you’re running QEMU under tmux & your prefix binding collidese with QEMU, use prefix+prefix+shortcut (the extra prefix goes through to QEMU)
- busybox is a small self contained set of utilites
- docker -v volume to share a dir with the container
- docker –platform=arch for a cross arch container
- “Then what does it mean to “give a Linux bridge an IP address”? In the Linux implementation, the bridge is not a separate hardware device (like they originally were), it’s also accessible from the host itself. That means it acts like a kind of “super-ethernet interface” with many ports, but packets that go into the kernel or out from this kernel to or from any of these ports reach the Linux OS under a single IP address”
- ICMP uses IP address of outgoing interface
- container_of struct macro to map a field back to a struct
- ftrace to trace functions (if you can’t see a function, it means it was inlined)
- pgrep to find a process by name (useful to do
gdb -p $(pgrep proc_name)
) - Have exit event in event loop
- atexit to register a destructor for the program
- setjmp, longjmp to save & restore context
- Use decltype in C++ when you don’t know the name of a type or when the syntax for expressing a type is cumbersome (looking at you function pointers)
- Rust ControlFlow gives a good basis for expressing structure for operations
- xargs for mapping many lines to many commandss
- stress-ng to stress test program
- /sys filesystem contains info about devices
- eventfd for being notified on events, userfaultfd to have usersapce pagefault handlers, irqfd’s for guest interrupts
- % is a wildcard in a makefile
- Linux device tree nodes (DTB file) can be used to reserver memory regions
- In C++, variables in anonymous namespaces have static visibility
- C++ header functions are implicitly inline
- “When your lockless algorithm uses many atomics, maybe time to make it use locks”
- acquire + release ordering for lock acquire relase
- lfence forces flush, sfence does not - lfence is serializing
- If one side has strong memory ordering, other side can have relaxed memory ordering
- gcc and clang lay out bitfields in opposite orders (!)
- .rodata section in ELF to store extra info specific to your toolchain
- (Obvious) you can’t reassign a reference in C++
- View threads in a debugger on attaching process to start debugging deadlocks
- PC relative offset in the ELF for relocations
- watchpoint in debuggers to debug memory corruption issues
- pre-commit run –files FILES to run on a file (useful after fixing conflicts after a rebase)
- When you want to pipe everything to a file use
cmd &> file
. - When you want to pipe everything into another cmd, use
cmd1 &> >(cmd2)
- Symbolic versioning
- Only lld supports multiple linker scripts
- CROSS_COMPILE prefix for specifying PREFIX-toolchain
- gcc -DCOMPILE_VAR=var_value
- Use if defined() instead of ifdef for proper conditional expressions: eg: if defined(var1) && !defined(var2)
-Wl,linker_arg=value
-Wl,-rpath
to add to rpath when compiling- If soname not present, then clang will link against absolute path
--sysroot
for toolchain to cross compile- In RISC-V, auipc+jalr calls are emitted by the compiler, which are then merged together by the linker (called “relaxation”)
gdb --ex 'cmd'
to run commands in gdb from commandline itself- C++ template polymorphism is syntactic (it doesn’t matter whether you’re calling a functor or a class or a function or a function pointer) & lazy
- Use phantom types when using ptr for lifetimes in structs
- Mutable references cannot be copied in Rust
git patch
apply to apply diffs.git apply --reverse diff
to apply a diff in reversegit add -p
to apply changes at a hunk granularity (i.e less than a file granularity)strace
to trace system calls- Nix can be combined with Docker for smaller images
$?
to get error code, «< to read stdin,$[@a]
- apt expects the repository to provide package for all given architectures, so an error in one means that package won’t be visible
- memfd to provide a memory file that can be shared with another process/etc
- (Not sure) If your dependencies load a library using RTLD_LOCAL, there may be multiple versions of the same symbol floating around
- objdump to view diassembly, symbols, ELF headers, etc. Similarly readelf
- QEMU: Single step
- Go runs C code in comments
- Choose the right type for your textures when using DirectX shaders, you may inadvertently be clamping values (eg:
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB
) - “RTLD_LOCAL is also transitive, meaning that the DT_NEEDED dependencies of a library opened with RTLD_LOCAL will themselves be loaded as RTLD_LOCAL and not added to the global scope.”
- dlsym actually looks at the return address on the stack to determine what the calling ELF object is.
- Use LD_PRELOAD + libsegfault.so to get backtraces on segfault without recompiling
- When you have a lock, can use relaxed memory ordering for any other atomics you have
- Compilers have –save-temps option when you want to inspect the different stages of compilation (macro preprocessing, IR, asm, object files, etc) – Rust has an include_bytes! macro to include the contents of a file as a container of bytes – It is undefined behavior to have a trivial infinite loop in C++, whereas it is perfectly legal in C