Skip to content

Commit d8e8e07

Browse files
committed
powerpc: Improve espresso fixup
The previous implementation naively patched all executable program segments and this had some unintended consequences (PR pkg/59928). Let's use the section header table to narrow the scope of the patching.
1 parent de3753d commit d8e8e07

File tree

4 files changed

+96
-39
lines changed

4 files changed

+96
-39
lines changed

libexec/ld.elf_so/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $NetBSD: Makefile,v 1.154 2026/01/09 22:54:27 jmcneill Exp $
1+
# $NetBSD: Makefile,v 1.155 2026/01/18 19:19:09 jmcneill Exp $
22
#
33
# NOTE: when changing ld.so, ensure that ldd still compiles.
44
#
@@ -122,7 +122,7 @@ CPPFLAGS+= -DHAVE_INITFINI_ARRAY
122122
.if ${LDELFSO_MACHINE_ARCH} == "powerpc"
123123
CPPFLAGS+= -DRTLD_MAP_OBJECT_FIXUP
124124
.endif
125-
#CPFLAGS+= -DDEBUG
125+
#CPPFLAGS+= -DDEBUG
126126
#CPPFLAGS+= -DRTLD_DEBUG
127127
#CPPFLAGS+= -DRTLD_DEBUG_RELOC
128128
#CPPFLAGS+= -DMALLOC_DEBUG

libexec/ld.elf_so/arch/powerpc/fixup.c

Lines changed: 88 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: fixup.c,v 1.2 2026/01/15 22:13:32 jmcneill Exp $ */
1+
/* $NetBSD: fixup.c,v 1.3 2026/01/18 19:19:09 jmcneill Exp $ */
22

33
/*-
44
* Copyright (c) 2026 Jared McNeill <jmcneill@invisible.ca>
@@ -28,7 +28,7 @@
2828

2929
#include <sys/cdefs.h>
3030
#ifndef lint
31-
__RCSID("$NetBSD: fixup.c,v 1.2 2026/01/15 22:13:32 jmcneill Exp $");
31+
__RCSID("$NetBSD: fixup.c,v 1.3 2026/01/18 19:19:09 jmcneill Exp $");
3232
#endif
3333

3434
#include <sys/types.h>
@@ -61,43 +61,16 @@ union instr {
6161

6262
#define IBMESPRESSO_P(_pvr) (((_pvr) >> 16) == 0x7001)
6363

64-
int
65-
_rtld_map_segment_fixup(Elf_Phdr *phdr, caddr_t data_addr, size_t data_size,
66-
int data_prot)
64+
static int
65+
_rtld_espresso_fixup_range(caddr_t data_addr, size_t data_size, int data_prot)
6766
{
68-
uint32_t *start, *where, *end;
67+
uint32_t *start, *end, *where;
6968
union instr previ;
7069

71-
if (!_rtld_fixup_init) {
72-
ssize_t i;
73-
size_t j;
74-
75-
j = sizeof(_rtld_ppc_pvr);
76-
i = _rtld_sysctl("machdep.pvr", &_rtld_ppc_pvr, &j);
77-
if (i != CTLTYPE_INT) {
78-
_rtld_ppc_pvr = 0;
79-
}
80-
j = sizeof(_rtld_ncpus);
81-
i = _rtld_sysctl("hw.ncpu", &_rtld_ncpus, &j);
82-
if (i != CTLTYPE_INT) {
83-
_rtld_ncpus = 1;
84-
}
85-
86-
_rtld_fixup_init = true;
87-
}
88-
if (!IBMESPRESSO_P(_rtld_ppc_pvr) || _rtld_ncpus == 1) {
89-
return 0;
90-
}
91-
if ((phdr->p_flags & PF_X) == 0) {
92-
return 0;
93-
}
94-
9570
start = (uint32_t *)data_addr;
9671
end = start + data_size / sizeof(*where);
9772
previ.i_int = 0;
9873

99-
dbg(("fixup (espresso) from %p to %p\n", start, end));
100-
10174
if ((data_prot & PROT_WRITE) == 0 &&
10275
mprotect(start, data_size, data_prot | PROT_WRITE) == -1) {
10376
_rtld_error("Cannot write-enable segment: %s",
@@ -143,3 +116,86 @@ _rtld_map_segment_fixup(Elf_Phdr *phdr, caddr_t data_addr, size_t data_size,
143116

144117
return 0;
145118
}
119+
120+
static int
121+
_rtld_espresso_fixup(const char *path, int fd, Elf_Ehdr *ehdr, Elf_Phdr *phdr,
122+
caddr_t data_addr, size_t data_size, int data_prot)
123+
{
124+
Elf_Shdr *shdr;
125+
size_t shdr_size;
126+
int i;
127+
128+
if (_rtld_ncpus == 1 || ehdr->e_shnum == 0 ||
129+
(phdr->p_flags & PF_X) == 0) {
130+
return 0;
131+
}
132+
133+
shdr_size = (size_t)ehdr->e_shentsize * ehdr->e_shnum;
134+
shdr = mmap(NULL, shdr_size, PROT_READ, MAP_FILE | MAP_SHARED, fd,
135+
ehdr->e_shoff);
136+
if (shdr == MAP_FAILED) {
137+
_rtld_error("%s: mmap of shdr failed: %s", path,
138+
xstrerror(errno));
139+
return -1;
140+
}
141+
142+
for (i = 0; i < ehdr->e_shnum; i++) {
143+
Elf_Addr start = shdr[i].sh_addr;
144+
Elf_Addr end = shdr[i].sh_addr + shdr[i].sh_size - 1;
145+
146+
if (shdr[i].sh_type != SHT_PROGBITS) {
147+
continue;
148+
}
149+
if ((shdr[i].sh_flags & SHF_EXECINSTR) == 0) {
150+
continue;
151+
}
152+
153+
if (start >= phdr->p_vaddr &&
154+
end < phdr->p_vaddr + phdr->p_filesz) {
155+
dbg(("%s: fixup (espresso) from %p to %p", path,
156+
(void *)start, (void *)end));
157+
158+
if (_rtld_espresso_fixup_range(
159+
data_addr + (start - phdr->p_vaddr),
160+
shdr[i].sh_size, data_prot) != 0) {
161+
_rtld_error("%s: fixup failed", path);
162+
munmap(shdr, shdr_size);
163+
return -1;
164+
}
165+
}
166+
}
167+
168+
munmap(shdr, shdr_size);
169+
170+
return 0;
171+
}
172+
173+
int
174+
_rtld_map_segment_fixup(const char *path, int fd, Elf_Ehdr *ehdr,
175+
Elf_Phdr *phdr, caddr_t data_addr, size_t data_size, int data_prot)
176+
{
177+
if (!_rtld_fixup_init) {
178+
ssize_t i;
179+
size_t j;
180+
181+
j = sizeof(_rtld_ppc_pvr);
182+
i = _rtld_sysctl("machdep.pvr", &_rtld_ppc_pvr, &j);
183+
if (i != CTLTYPE_INT) {
184+
_rtld_ppc_pvr = 0;
185+
}
186+
j = sizeof(_rtld_ncpus);
187+
i = _rtld_sysctl("hw.ncpu", &_rtld_ncpus, &j);
188+
if (i != CTLTYPE_INT) {
189+
_rtld_ncpus = 1;
190+
}
191+
192+
_rtld_fixup_init = true;
193+
}
194+
195+
if (IBMESPRESSO_P(_rtld_ppc_pvr)) {
196+
return _rtld_espresso_fixup(path, fd, ehdr, phdr, data_addr,
197+
data_size, data_prot);
198+
}
199+
200+
return 0;
201+
}

libexec/ld.elf_so/map_object.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: map_object.c,v 1.70 2026/01/09 22:54:27 jmcneill Exp $ */
1+
/* $NetBSD: map_object.c,v 1.71 2026/01/18 19:19:09 jmcneill Exp $ */
22

33
/*
44
* Copyright 1996 John D. Polstra.
@@ -34,7 +34,7 @@
3434

3535
#include <sys/cdefs.h>
3636
#ifndef lint
37-
__RCSID("$NetBSD: map_object.c,v 1.70 2026/01/09 22:54:27 jmcneill Exp $");
37+
__RCSID("$NetBSD: map_object.c,v 1.71 2026/01/18 19:19:09 jmcneill Exp $");
3838
#endif /* not lint */
3939

4040
#include <errno.h>
@@ -367,7 +367,7 @@ _rtld_map_object(const char *path, int fd, const struct stat *sb)
367367
}
368368

369369
#ifdef RTLD_MAP_OBJECT_FIXUP
370-
if (_rtld_map_segment_fixup(segs[i], data_addr,
370+
if (_rtld_map_segment_fixup(path, fd, ehdr, segs[i], data_addr,
371371
data_vlimit - data_vaddr,
372372
data_prot) == -1) {
373373
goto error;

libexec/ld.elf_so/rtld.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: rtld.h,v 1.153 2026/01/12 13:54:48 nia Exp $ */
1+
/* $NetBSD: rtld.h,v 1.154 2026/01/18 19:19:09 jmcneill Exp $ */
22

33
/*
44
* Copyright 1996 John D. Polstra.
@@ -427,7 +427,8 @@ int _rtld_load_needed_objects(Obj_Entry *, int);
427427
int _rtld_preload(const char *);
428428

429429
/* arch/<arch>/fixup.c */
430-
int _rtld_map_segment_fixup(Elf_Phdr *, caddr_t, size_t, int);
430+
int _rtld_map_segment_fixup(const char *, int, Elf_Ehdr *, Elf_Phdr *,
431+
caddr_t, size_t, int);
431432

432433
#define OBJ_ERR (Obj_Entry *)(-1)
433434
/* path.c */

0 commit comments

Comments
 (0)