diff --git a/0001-profile-Use-base-vaddr-for-__llvm_write_binary_ids-n.patch b/0001-profile-Use-base-vaddr-for-__llvm_write_binary_ids-n.patch new file mode 100644 index 0000000..7f0a7cf --- /dev/null +++ b/0001-profile-Use-base-vaddr-for-__llvm_write_binary_ids-n.patch @@ -0,0 +1,86 @@ +From ccc2b792e57d632bc887b226a4e7f0a8189eab8b Mon Sep 17 00:00:00 2001 +From: Josh Stone +Date: Mon, 4 Nov 2024 16:37:49 -0800 +Subject: [PATCH] [profile] Use base+vaddr for `__llvm_write_binary_ids` note + pointers + +This function is always examining its own ELF headers in memory, but it +was trying to use conditions between examining files or memory, and it +wasn't accounting for LOAD offsets at runtime. This is especially bad if +a loaded segment has additional padding that's not in the file offsets. + +Now we do a first scan of the program headers to figure out the runtime +base address based on `PT_PHDR` and/or `PT_DYNAMIC` (else assume zero), +similar to libc's `do_start`. Then each `PT_NOTE` pointer is simply the +base plus the segments's `pt_vaddr`, which includes LOAD offsets. + +Fixes #114605 +--- + .../lib/profile/InstrProfilingPlatformLinux.c | 40 ++++++++----------- + 1 file changed, 16 insertions(+), 24 deletions(-) + +diff --git a/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c +index e2c06d51e0c6..c365129a0768 100644 +--- a/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c ++++ b/compiler-rt/lib/profile/InstrProfilingPlatformLinux.c +@@ -194,41 +194,33 @@ static int WriteBinaryIds(ProfDataWriter *Writer, const ElfW(Nhdr) * Note, + */ + COMPILER_RT_VISIBILITY int __llvm_write_binary_ids(ProfDataWriter *Writer) { + extern const ElfW(Ehdr) __ehdr_start __attribute__((visibility("hidden"))); ++ extern ElfW(Dyn) _DYNAMIC[] __attribute__((weak, visibility("hidden"))); ++ + const ElfW(Ehdr) *ElfHeader = &__ehdr_start; + const ElfW(Phdr) *ProgramHeader = + (const ElfW(Phdr) *)((uintptr_t)ElfHeader + ElfHeader->e_phoff); + ++ /* Compute the added base address in case of position-independent code. */ ++ uintptr_t Base = 0; ++ for (uint32_t I = 0; I < ElfHeader->e_phnum; I++) { ++ if (ProgramHeader[I].p_type == PT_PHDR) ++ Base = (uintptr_t)ProgramHeader - ProgramHeader[I].p_vaddr; ++ if (ProgramHeader[I].p_type == PT_DYNAMIC && _DYNAMIC) ++ Base = (uintptr_t)_DYNAMIC - ProgramHeader[I].p_vaddr; ++ } ++ + int TotalBinaryIdsSize = 0; +- uint32_t I; + /* Iterate through entries in the program header. */ +- for (I = 0; I < ElfHeader->e_phnum; I++) { ++ for (uint32_t I = 0; I < ElfHeader->e_phnum; I++) { + /* Look for the notes segment in program header entries. */ + if (ProgramHeader[I].p_type != PT_NOTE) + continue; + + /* There can be multiple notes segment, and examine each of them. */ +- const ElfW(Nhdr) * Note; +- const ElfW(Nhdr) * NotesEnd; +- /* +- * When examining notes in file, use p_offset, which is the offset within +- * the elf file, to find the start of notes. +- */ +- if (ProgramHeader[I].p_memsz == 0 || +- ProgramHeader[I].p_memsz == ProgramHeader[I].p_filesz) { +- Note = (const ElfW(Nhdr) *)((uintptr_t)ElfHeader + +- ProgramHeader[I].p_offset); +- NotesEnd = (const ElfW(Nhdr) *)((const char *)(Note) + +- ProgramHeader[I].p_filesz); +- } else { +- /* +- * When examining notes in memory, use p_vaddr, which is the address of +- * section after loaded to memory, to find the start of notes. +- */ +- Note = +- (const ElfW(Nhdr) *)((uintptr_t)ElfHeader + ProgramHeader[I].p_vaddr); +- NotesEnd = +- (const ElfW(Nhdr) *)((const char *)(Note) + ProgramHeader[I].p_memsz); +- } ++ const ElfW(Nhdr) *Note = ++ (const ElfW(Nhdr) *)(Base + ProgramHeader[I].p_vaddr); ++ const ElfW(Nhdr) *NotesEnd = ++ (const ElfW(Nhdr) *)((const char *)(Note) + ProgramHeader[I].p_memsz); + + int BinaryIdsSize = WriteBinaryIds(Writer, Note, NotesEnd); + if (TotalBinaryIdsSize == -1) +-- +2.47.0 + diff --git a/llvm.spec b/llvm.spec index ebd5952..0142711 100644 --- a/llvm.spec +++ b/llvm.spec @@ -182,7 +182,7 @@ #region main package Name: %{pkg_name_llvm} Version: %{maj_ver}.%{min_ver}.%{patch_ver}%{?rc_ver:~rc%{rc_ver}}%{?llvm_snapshot_version_suffix:~%{llvm_snapshot_version_suffix}} -Release: 2%{?dist} +Release: 3%{?dist} Summary: The Low Level Virtual Machine License: Apache-2.0 WITH LLVM-exception OR NCSA @@ -277,6 +277,12 @@ Patch501: 0001-Fix-page-size-constant-on-aarch64-and-ppc64le.patch # Fixes RHEL-49517. Patch1801: 18-99273.patch +# Fix profiling after a binutils NOTE change. +# https://github.com/llvm/llvm-project/pull/114907 +Patch1802: 0001-profile-Use-base-vaddr-for-__llvm_write_binary_ids-n.patch +Patch1903: 0001-profile-Use-base-vaddr-for-__llvm_write_binary_ids-n.patch +Patch2001: 0001-profile-Use-base-vaddr-for-__llvm_write_binary_ids-n.patch + %if 0%{?rhel} == 8 %global python3_pkgversion 3.12 %global __python3 /usr/bin/python3.12 @@ -2472,6 +2478,9 @@ fi #region changelog %changelog +* Mon Nov 18 2024 Josh Stone - 19.1.3-3 +- Fix profiling after a binutils NOTE change (rhbz#2322754) + * Mon Nov 18 2024 Timm Bäder - 19.1.3-2 - Install i386 config files on x86_64