# Struct Layout Analysis

> Measure and fix C struct layout in BIND 9 — pahole on the build's DWARF for sizes, padding holes, and cacheline boundaries, plus the house cacheline-padding idiom. Use when asked about struct size, padding, false sharing, or when adding/reordering members in hot structures.

- Skill: `isc-projects/struct-layout-analysis` (Agent Skill)
- Install (CLI): `npx skillmds@latest add isc-projects/struct-layout-analysis`
- Raw SKILL.md: https://api.skillmd.com/api/skills/isc-projects/struct-layout-analysis/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: isc-projects (https://skillmd.com/u/isc-projects)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/isc-projects/struct-layout-analysis

---


# Struct layout: measure with pahole, pad with a multiplier

## Measuring — pahole, never throwaway sizeof programs

The developer build (`-Og -ggdb`) already carries DWARF; read it
instead of compiling sizeof/offsetof snippets:

```sh
pahole -C <struct_name> build/lib/dns/libdns*.so.p/<file>.c.o
pahole --holes -C <struct_name> <object-or-binary>
```

pahole prints member offsets, padding holes, total size, and cacheline
boundaries — complete layout information the compiler already computed,
with no boilerplate to write. Any object file under `build/` or the
final binary works as input.

## Padding to cachelines — union arm with a plain multiplier

Pad a struct to a whole number of cache lines with a union arm sized by
a plain multiplier, always paired with a static assert:

```c
struct foo {
	union {
		struct {
			/* members */
		};
		uint8_t __padding[ISC_OS_CACHELINE_SIZE * 6];
	};
};
STATIC_ASSERT(sizeof(struct foo) % ISC_OS_CACHELINE_SIZE == 0,
	      "struct foo size must be a multiple of the cacheline size");
```

Pick the smallest `n` that fits; when members outgrow the arm to a
non-multiple size, the STATIC_ASSERT fires and prompts a bump of `n`.

Do NOT use the enumerated-sizeof trailing formula
`uint8_t __padding[CACHELINE - (sizeof(a) + sizeof(b) + ...) % CACHELINE]`
(the historical qpzone style): it must enumerate every member's sizeof,
so adding a member silently miscounts unless the formula is updated in
lockstep. The multiplier form has no such coupling and is easier to
read.

