link_image_id.c (2060B)
1 /* link_image_id_compute: format-agnostic 16-byte identity hash for a 2 * resolved LinkImage. 3 * 4 * A single SHA-256 stream is fed each segment's vaddr, file_size, and 5 * post-shift bytes, so the digest changes if either content or layout 6 * shifts. The 16-byte image id is the first half of the 32-byte digest. 7 * The SHA-256 core uses the AArch64 crypto extension where the host has 8 * it (the same hardware path that hashes the Mach-O code signature), so 9 * the per-byte fold is far cheaper than the old twin-FNV mix — this was 10 * the residual top frame on pathologically large links. Determinism (no 11 * time / random component) is intentional — reproducible builds. 12 * 13 * Wrapped per format: 14 * - ELF .note.gnu.build-id (link_emit_elf) 15 * - Mach-O LC_UUID payload (link_emit_macho, Phase 3) 16 * - COFF/PE debug directory (deferred) 17 * 18 * Lived in link_elf.c through Phase 0; lifted out so the Mach-O writer 19 * sees the same bytes. */ 20 21 #include "core/core.h" 22 #include "core/sha256.h" 23 #include "link/link_internal.h" 24 25 /* sha256_update takes a u32 length; feed large segments in chunks so a 26 * >4 GiB segment can never truncate the stream. */ 27 static void image_id_update(Sha256* s, const u8* data, size_t n) { 28 while (n) { 29 u32 chunk = n > 0x40000000u ? 0x40000000u : (u32)n; 30 sha256_update(s, data, chunk); 31 data += chunk; 32 n -= chunk; 33 } 34 } 35 36 void link_image_id_compute(const LinkImage* img, u8 out[LINK_IMAGE_ID_BYTES]) { 37 Sha256 s; 38 sha256_init(&s); 39 u32 i; 40 for (i = 0; i < img->nsegments; ++i) { 41 const LinkSegment* seg = &img->segments[i]; 42 u64 vaddr = seg->vaddr; 43 u64 fsz = seg->file_size; 44 sha256_update(&s, (const u8*)&vaddr, (u32)sizeof vaddr); 45 sha256_update(&s, (const u8*)&fsz, (u32)sizeof fsz); 46 if (img->segment_bytes[i] && fsz) 47 image_id_update(&s, img->segment_bytes[i], (size_t)fsz); 48 } 49 u8 digest[SHA256_DIGEST_LEN]; 50 sha256_final(&s, digest); 51 /* Image id is the first 16 bytes of the 256-bit digest. */ 52 for (i = 0; i < LINK_IMAGE_ID_BYTES; ++i) out[i] = digest[i]; 53 }