mirror of
git://sourceware.org/git/glibc.git
synced 2026-09-09 11:58:23 +08:00
Compare commits
182
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42c99ba55f | ||
|
|
829e179a52 | ||
|
|
8a4566d712 | ||
|
|
7a76b94bab | ||
|
|
a6e4d0bbd7 | ||
|
|
c5872cb18b | ||
|
|
3295936b27 | ||
|
|
782fb76092 | ||
|
|
8593166279 | ||
|
|
bf969db943 | ||
|
|
a46c1b96f3 | ||
|
|
0e893e3d68 | ||
|
|
057a635835 | ||
|
|
45b4ae2ffd | ||
|
|
e8d0e61aa2 | ||
|
|
df30ef1b0d | ||
|
|
cef9089a68 | ||
|
|
b2854b0bcc | ||
|
|
40b60cc1db | ||
|
|
44283b4f2f | ||
|
|
418ede06d7 | ||
|
|
dac0b184e7 | ||
|
|
28f19db3b8 | ||
|
|
78412dcc6a | ||
|
|
4ad4ea848b | ||
|
|
f660eb9cc7 | ||
|
|
1fa257f338 | ||
|
|
cdba5ffdae | ||
|
|
f54124b801 | ||
|
|
3d959e4b0e | ||
|
|
c0a839639b | ||
|
|
0648dbf3a0 | ||
|
|
bbfb104b50 | ||
|
|
66e78c5b74 | ||
|
|
4d7cf069ee | ||
|
|
9c11d64d6d | ||
|
|
b35504abf0 | ||
|
|
f0e8f3667c | ||
|
|
ab0bc274aa | ||
|
|
9912e5c608 | ||
|
|
e841326457 | ||
|
|
a1d26f7b1d | ||
|
|
e6a2c4c4bb | ||
|
|
87dffcda13 | ||
|
|
a66d563c9e | ||
|
|
74085ebc1f | ||
|
|
1b0716e083 | ||
|
|
55ada9157d | ||
|
|
11e0080cd5 | ||
|
|
bb624b6c43 | ||
|
|
8d2bab6e17 | ||
|
|
d5f9769d53 | ||
|
|
009e1fd306 | ||
|
|
a3085f72f8 | ||
|
|
456f4dd6e5 | ||
|
|
a2d8296886 | ||
|
|
73f47b6560 | ||
|
|
bfc66c9896 | ||
|
|
284e4f1755 | ||
|
|
afbfdd28bd | ||
|
|
c3d2d246c5 | ||
|
|
94f15a4231 | ||
|
|
cb2ecefc21 | ||
|
|
85c6eba32a | ||
|
|
059dd1983c | ||
|
|
ed157fcccd | ||
|
|
fbc8167346 | ||
|
|
37cfa707b0 | ||
|
|
00f9cd1a70 | ||
|
|
2f3bf4cf63 | ||
|
|
ccce788403 | ||
|
|
5ef98a9900 | ||
|
|
a8989aef06 | ||
|
|
7f9c78bc3a | ||
|
|
7dac60585d | ||
|
|
6cca02f732 | ||
|
|
2b9e393156 | ||
|
|
d74b162292 | ||
|
|
f4fe4afdf0 | ||
|
|
3be82efc58 | ||
|
|
cec148df6f | ||
|
|
d8173e2496 | ||
|
|
bb648757f0 | ||
|
|
989eb50954 | ||
|
|
93ab84cd80 | ||
|
|
3eb1c569eb | ||
|
|
6f93421a5f | ||
|
|
392f32c841 | ||
|
|
d15c9f859f | ||
|
|
51fe1e15ed | ||
|
|
2b1192cae0 | ||
|
|
06fda78445 | ||
|
|
a0cbaef87c | ||
|
|
4f45607de9 | ||
|
|
c755eefac5 | ||
|
|
c779cc818e | ||
|
|
ec5240f821 | ||
|
|
89ab8ac121 | ||
|
|
257781e305 | ||
|
|
6af67120e8 | ||
|
|
84068c087b | ||
|
|
4064e7a4fc | ||
|
|
b3d26f52f7 | ||
|
|
0205012984 | ||
|
|
d0db1e8a12 | ||
|
|
68822420a6 | ||
|
|
159a76a8dd | ||
|
|
f7842f9392 | ||
|
|
5778537ccd | ||
|
|
01faa1bcd4 | ||
|
|
63bee6f155 | ||
|
|
f29dda01e0 | ||
|
|
b38585301d | ||
|
|
c8f1fc9d94 | ||
|
|
7880bbd374 | ||
|
|
d63bc8be87 | ||
|
|
d257d001c3 | ||
|
|
8536404f41 | ||
|
|
8022e6934e | ||
|
|
a4f02d3f68 | ||
|
|
091bcf0e1c | ||
|
|
823a9cb203 | ||
|
|
bb5bc76947 | ||
|
|
110733491a | ||
|
|
4275aff6b8 | ||
|
|
cb79f5073a | ||
|
|
887a33c6bb | ||
|
|
ff2cd89ebb | ||
|
|
347f7e2ac1 | ||
|
|
d77736297a | ||
|
|
2d0278e6d7 | ||
|
|
822571c5b1 | ||
|
|
9f92fe592b | ||
|
|
fb41a562bf | ||
|
|
ed90470cc0 | ||
|
|
d23dfc0324 | ||
|
|
ff371935db | ||
|
|
9ef71c0be0 | ||
|
|
2d17978865 | ||
|
|
fbdd679dfe | ||
|
|
dd44f97920 | ||
|
|
30d6fef4c7 | ||
|
|
05c7fd2959 | ||
|
|
df91141390 | ||
|
|
2e1fc3bdee | ||
|
|
0ae704caef | ||
|
|
538a80eaf4 | ||
|
|
42ab155048 | ||
|
|
424b0ffa6f | ||
|
|
bec24b66e8 | ||
|
|
d496a3dd55 | ||
|
|
750a8bb78b | ||
|
|
3a0ce7aeb0 | ||
|
|
eca95865e3 | ||
|
|
e8728f756a | ||
|
|
db037e48fb | ||
|
|
434271f132 | ||
|
|
93c5545300 | ||
|
|
77777d453d | ||
|
|
78cc285037 | ||
|
|
ccec84f408 | ||
|
|
9e6811dafb | ||
|
|
18fb025070 | ||
|
|
4fc4072240 | ||
|
|
570f6858b7 | ||
|
|
084ac620b1 | ||
|
|
2adfa58c4f | ||
|
|
f8335dc69a | ||
|
|
1cb2ecf162 | ||
|
|
a87b3fcbb3 | ||
|
|
30719666f8 | ||
|
|
1943345fa3 | ||
|
|
dec33ea23f | ||
|
|
db674b0d98 | ||
|
|
d8ecbea3fc | ||
|
|
14c8e3a355 | ||
|
|
2f90599f89 | ||
|
|
9ed39f584e | ||
|
|
9f22387b95 | ||
|
|
c74bb93cfd | ||
|
|
33f1b4c145 | ||
|
|
c3fda489cf |
@@ -1002,7 +1002,7 @@ endef
|
||||
define make-link-multidir
|
||||
$(patsubst %/,cd %,$(objpfx)); \
|
||||
$(addprefix $(abspath $(..)scripts/mkinstalldirs) ,$(dir $(multidir))); \
|
||||
$(LN_S) . $(multidir) 2> /dev/null; \
|
||||
$(SHELL) $(abspath $(..)scripts/rellns-sh) . $(multidir) 2> /dev/null; \
|
||||
test -L $(multidir)
|
||||
endef
|
||||
else
|
||||
|
||||
@@ -4,6 +4,13 @@ See the end for copying conditions.
|
||||
|
||||
Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
|
||||
using `glibc' in the "product" field.
|
||||
|
||||
Version 2.36.1
|
||||
|
||||
The following bugs are resolved with this release:
|
||||
|
||||
[29446] _dlopen now ignores dl_caller argument in static mode
|
||||
|
||||
|
||||
Version 2.36
|
||||
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@
|
||||
#define __SYSCALL_ULONG_TYPE __ULONGWORD_TYPE
|
||||
#define __CPU_MASK_TYPE __ULONGWORD_TYPE
|
||||
|
||||
#ifdef __LP64__
|
||||
#if defined __LP64__ || defined __CHERI_PURE_CAPABILITY__
|
||||
/* Tell the libc code that off_t and off64_t are actually the same type
|
||||
for all ABI purposes, even if possibly expressed as different base types
|
||||
for C type-checking purposes. */
|
||||
|
||||
+19
-3
@@ -132,15 +132,15 @@ call_init (int argc, char **argv, char **env)
|
||||
the same file. */
|
||||
|
||||
if (ELF_INITFINI && l->l_info[DT_INIT] != NULL)
|
||||
DL_CALL_DT_INIT(l, l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr,
|
||||
DL_CALL_DT_INIT(l, dl_rx_ptr (l, l->l_info[DT_INIT]->d_un.d_ptr),
|
||||
argc, argv, env);
|
||||
|
||||
ElfW(Dyn) *init_array = l->l_info[DT_INIT_ARRAY];
|
||||
if (init_array != NULL)
|
||||
{
|
||||
unsigned int jm
|
||||
= l->l_info[DT_INIT_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr));
|
||||
ElfW(Addr) *addrs = (void *) (init_array->d_un.d_ptr + l->l_addr);
|
||||
= l->l_info[DT_INIT_ARRAYSZ]->d_un.d_val / sizeof (elfptr_t);
|
||||
elfptr_t *addrs = (void *) dl_rx_ptr (l, init_array->d_un.d_ptr);
|
||||
for (unsigned int j = 0; j < jm; ++j)
|
||||
((dl_init_t) addrs[j]) (argc, argv, env);
|
||||
}
|
||||
@@ -210,11 +210,16 @@ STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
|
||||
MAIN_AUXVEC_DECL),
|
||||
int argc,
|
||||
char **argv,
|
||||
#ifdef LIBC_START_MAIN_ENVP_ARG
|
||||
char **envp,
|
||||
#endif
|
||||
#ifdef LIBC_START_MAIN_AUXVEC_ARG
|
||||
ElfW(auxv_t) *auxvec,
|
||||
#endif
|
||||
#ifndef LIBC_START_MAIN_NO_INITFINI_ARG
|
||||
__typeof (main) init,
|
||||
void (*fini) (void),
|
||||
#endif
|
||||
void (*rtld_fini) (void),
|
||||
void *stack_end)
|
||||
__attribute__ ((noreturn));
|
||||
@@ -233,15 +238,24 @@ STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
|
||||
STATIC int
|
||||
LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
|
||||
int argc, char **argv,
|
||||
#ifdef LIBC_START_MAIN_ENVP_ARG
|
||||
char **envp,
|
||||
#endif
|
||||
#ifdef LIBC_START_MAIN_AUXVEC_ARG
|
||||
ElfW(auxv_t) *auxvec,
|
||||
#endif
|
||||
#ifndef LIBC_START_MAIN_NO_INITFINI_ARG
|
||||
__typeof (main) init,
|
||||
void (*fini) (void),
|
||||
#endif
|
||||
void (*rtld_fini) (void), void *stack_end)
|
||||
{
|
||||
#ifndef SHARED
|
||||
#ifdef LIBC_START_MAIN_ENVP_ARG
|
||||
char **ev = envp;
|
||||
#else
|
||||
char **ev = &argv[argc + 1];
|
||||
#endif
|
||||
|
||||
__environ = ev;
|
||||
|
||||
@@ -358,11 +372,13 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
|
||||
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
|
||||
GLRO(dl_debug_printf) ("\ninitialize program: %s\n\n", argv[0]);
|
||||
|
||||
#ifndef LIBC_START_MAIN_NO_INITFINI_ARG
|
||||
if (init != NULL)
|
||||
/* This is a legacy program which supplied its own init
|
||||
routine. */
|
||||
(*init) (argc, argv, __environ MAIN_AUXVEC_PARAM);
|
||||
else
|
||||
#endif
|
||||
/* This is a current program. Use the dynamic segment to find
|
||||
constructors. */
|
||||
call_init (argc, argv, __environ);
|
||||
|
||||
+1
-1
@@ -125,7 +125,7 @@ __libc_setup_tls (void)
|
||||
/* Remember the values we need. */
|
||||
memsz = phdr->p_memsz;
|
||||
filesz = phdr->p_filesz;
|
||||
initimage = (void *) phdr->p_vaddr + main_map->l_addr;
|
||||
initimage = (void *) dl_rx_ptr (main_map, phdr->p_vaddr);
|
||||
align = phdr->p_align;
|
||||
if (phdr->p_align > max_align)
|
||||
max_align = phdr->p_align;
|
||||
|
||||
+1
-2
@@ -28,13 +28,12 @@ __wcpcpy_chk (wchar_t *dest, const wchar_t *src, size_t destlen)
|
||||
{
|
||||
wchar_t *wcp = (wchar_t *) dest - 1;
|
||||
wint_t c;
|
||||
const ptrdiff_t off = src - dest + 1;
|
||||
|
||||
do
|
||||
{
|
||||
if (__glibc_unlikely (destlen-- == 0))
|
||||
__chk_fail ();
|
||||
c = wcp[off];
|
||||
c = *src++;
|
||||
*++wcp = c;
|
||||
}
|
||||
while (c != L'\0');
|
||||
|
||||
+7
-27
@@ -24,36 +24,16 @@ wchar_t *
|
||||
__wcscpy_chk (wchar_t *dest, const wchar_t *src, size_t n)
|
||||
{
|
||||
wint_t c;
|
||||
wchar_t *wcp;
|
||||
wchar_t *wcp = dest;
|
||||
|
||||
if (__alignof__ (wchar_t) >= sizeof (wchar_t))
|
||||
do
|
||||
{
|
||||
const ptrdiff_t off = dest - src - 1;
|
||||
|
||||
wcp = (wchar_t *) src;
|
||||
|
||||
do
|
||||
{
|
||||
if (__glibc_unlikely (n-- == 0))
|
||||
__chk_fail ();
|
||||
c = *wcp++;
|
||||
wcp[off] = c;
|
||||
}
|
||||
while (c != L'\0');
|
||||
}
|
||||
else
|
||||
{
|
||||
wcp = dest;
|
||||
|
||||
do
|
||||
{
|
||||
if (__glibc_unlikely (n-- == 0))
|
||||
__chk_fail ();
|
||||
c = *src++;
|
||||
*wcp++ = c;
|
||||
}
|
||||
while (c != L'\0');
|
||||
if (__glibc_unlikely (n-- == 0))
|
||||
__chk_fail ();
|
||||
c = *src++;
|
||||
*wcp++ = c;
|
||||
}
|
||||
while (c != L'\0');
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ compat_symbol (libdl, ___dlopen, dlopen, GLIBC_2_1);
|
||||
void *
|
||||
__dlopen (const char *file, int mode, void *dl_caller)
|
||||
{
|
||||
return dlopen_implementation (file, mode, RETURN_ADDRESS (0));
|
||||
return dlopen_implementation (file, mode, dl_caller);
|
||||
}
|
||||
|
||||
void *
|
||||
|
||||
@@ -210,6 +210,9 @@ print_entry (const char *lib, int flag, uint64_t hwcap,
|
||||
case FLAG_AARCH64_LIB64:
|
||||
fputs (",AArch64", stdout);
|
||||
break;
|
||||
case FLAG_AARCH64_PURECAP:
|
||||
fputs (",purecap", stdout);
|
||||
break;
|
||||
/* Uses the ARM soft-float ABI. */
|
||||
case FLAG_ARM_LIBSF:
|
||||
fputs (",soft-float", stdout);
|
||||
|
||||
+4
-6
@@ -119,11 +119,10 @@ call_destructors (void *closure)
|
||||
|
||||
if (map->l_info[DT_FINI_ARRAY] != NULL)
|
||||
{
|
||||
ElfW(Addr) *array =
|
||||
(ElfW(Addr) *) (map->l_addr
|
||||
+ map->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
|
||||
elfptr_t *array =
|
||||
(elfptr_t *) dl_rx_ptr (map, map->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
|
||||
unsigned int sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
|
||||
/ sizeof (ElfW(Addr)));
|
||||
/ sizeof (elfptr_t));
|
||||
|
||||
while (sz-- > 0)
|
||||
((fini_t) array[sz]) ();
|
||||
@@ -131,8 +130,7 @@ call_destructors (void *closure)
|
||||
|
||||
/* Next try the old-style destructor. */
|
||||
if (map->l_info[DT_FINI] != NULL)
|
||||
DL_CALL_DT_FINI (map, ((void *) map->l_addr
|
||||
+ map->l_info[DT_FINI]->d_un.d_ptr));
|
||||
DL_CALL_DT_FINI (map, dl_rx_ptr (map, map->l_info[DT_FINI]->d_un.d_ptr));
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -105,7 +105,7 @@ _dl_find_object_from_map (struct link_map *l,
|
||||
if (ph->p_type == DLFO_EH_SEGMENT_TYPE)
|
||||
{
|
||||
atomic_store_relaxed (&result->eh_frame,
|
||||
(void *) (ph->p_vaddr + l->l_addr));
|
||||
(void *) dl_rx_ptr (l, ph->p_vaddr));
|
||||
#if DLFO_STRUCT_HAS_EH_COUNT
|
||||
atomic_store_relaxed (&result->eh_count, ph->p_memsz / 8);
|
||||
#endif
|
||||
|
||||
+4
-5
@@ -133,11 +133,10 @@ _dl_fini (void)
|
||||
/* First see whether an array is given. */
|
||||
if (l->l_info[DT_FINI_ARRAY] != NULL)
|
||||
{
|
||||
ElfW(Addr) *array =
|
||||
(ElfW(Addr) *) (l->l_addr
|
||||
+ l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
|
||||
ElfW(Addr) v = l->l_info[DT_FINI_ARRAY]->d_un.d_ptr;
|
||||
elfptr_t *array = (elfptr_t *) dl_rx_ptr (l, v);
|
||||
unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
|
||||
/ sizeof (ElfW(Addr)));
|
||||
/ sizeof (elfptr_t));
|
||||
while (i-- > 0)
|
||||
((fini_t) array[i]) ();
|
||||
}
|
||||
@@ -145,7 +144,7 @@ _dl_fini (void)
|
||||
/* Next try the old-style destructor. */
|
||||
if (ELF_INITFINI && l->l_info[DT_FINI] != NULL)
|
||||
DL_CALL_DT_FINI
|
||||
(l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr);
|
||||
(l, dl_rx_ptr (l, l->l_info[DT_FINI]->d_un.d_ptr));
|
||||
}
|
||||
|
||||
#ifdef SHARED
|
||||
|
||||
+8
-7
@@ -53,7 +53,8 @@ call_init (struct link_map *l, int argc, char **argv, char **env)
|
||||
- the others in the DT_INIT_ARRAY.
|
||||
*/
|
||||
if (ELF_INITFINI && l->l_info[DT_INIT] != NULL)
|
||||
DL_CALL_DT_INIT(l, l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr, argc, argv, env);
|
||||
DL_CALL_DT_INIT(l, dl_rx_ptr (l, l->l_info[DT_INIT]->d_un.d_ptr),
|
||||
argc, argv, env);
|
||||
|
||||
/* Next see whether there is an array with initialization functions. */
|
||||
ElfW(Dyn) *init_array = l->l_info[DT_INIT_ARRAY];
|
||||
@@ -61,11 +62,11 @@ call_init (struct link_map *l, int argc, char **argv, char **env)
|
||||
{
|
||||
unsigned int j;
|
||||
unsigned int jm;
|
||||
ElfW(Addr) *addrs;
|
||||
elfptr_t *addrs;
|
||||
|
||||
jm = l->l_info[DT_INIT_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr));
|
||||
jm = l->l_info[DT_INIT_ARRAYSZ]->d_un.d_val / sizeof (elfptr_t);
|
||||
|
||||
addrs = (ElfW(Addr) *) (init_array->d_un.d_ptr + l->l_addr);
|
||||
addrs = (elfptr_t *) dl_rx_ptr (l, init_array->d_un.d_ptr);
|
||||
for (j = 0; j < jm; ++j)
|
||||
((dl_init_t) addrs[j]) (argc, argv, env);
|
||||
}
|
||||
@@ -88,16 +89,16 @@ _dl_init (struct link_map *main_map, int argc, char **argv, char **env)
|
||||
/* Don't do anything if there is no preinit array. */
|
||||
if (__builtin_expect (preinit_array != NULL, 0)
|
||||
&& preinit_array_size != NULL
|
||||
&& (i = preinit_array_size->d_un.d_val / sizeof (ElfW(Addr))) > 0)
|
||||
&& (i = preinit_array_size->d_un.d_val / sizeof (elfptr_t)) > 0)
|
||||
{
|
||||
ElfW(Addr) *addrs;
|
||||
elfptr_t *addrs;
|
||||
unsigned int cnt;
|
||||
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS))
|
||||
_dl_debug_printf ("\ncalling preinit: %s\n\n",
|
||||
DSO_FILENAME (main_map->l_name));
|
||||
|
||||
addrs = (ElfW(Addr) *) (preinit_array->d_un.d_ptr + main_map->l_addr);
|
||||
addrs = (elfptr_t *) dl_rx_ptr (main_map, preinit_array->d_un.d_ptr);
|
||||
for (cnt = 0; cnt < i; ++cnt)
|
||||
((dl_init_t) addrs[cnt]) (argc, argv, env);
|
||||
}
|
||||
|
||||
@@ -61,9 +61,20 @@ __dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info,
|
||||
|
||||
for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
|
||||
{
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
info.dlpi_addr = l->l_real->l_addr == l->l_real->l_map_start
|
||||
? l->l_real->l_map_start
|
||||
: l->l_real->l_addr;
|
||||
#else
|
||||
info.dlpi_addr = l->l_real->l_addr;
|
||||
#endif
|
||||
info.dlpi_name = l->l_real->l_name;
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
ElfW(Addr) phdr = (ElfW(Addr)) l->l_real->l_phdr - l->l_real->l_addr;
|
||||
info.dlpi_phdr = (const void *) dl_rx_ptr (l->l_real, phdr);
|
||||
#else
|
||||
info.dlpi_phdr = l->l_real->l_phdr;
|
||||
#endif
|
||||
info.dlpi_phnum = l->l_real->l_phnum;
|
||||
info.dlpi_adds = GL(dl_load_adds);
|
||||
info.dlpi_subs = GL(dl_load_adds) - nloaded;
|
||||
|
||||
+8
-5
@@ -866,7 +866,7 @@ _dl_init_paths (const char *llp, const char *source,
|
||||
void
|
||||
_dl_process_pt_gnu_property (struct link_map *l, int fd, const ElfW(Phdr) *ph)
|
||||
{
|
||||
const ElfW(Nhdr) *note = (const void *) (ph->p_vaddr + l->l_addr);
|
||||
const ElfW(Nhdr) *note = (const void *) dl_rx_ptr (l, ph->p_vaddr);
|
||||
const ElfW(Addr) size = ph->p_memsz;
|
||||
const ElfW(Addr) align = ph->p_align;
|
||||
|
||||
@@ -1276,7 +1276,9 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
|
||||
}
|
||||
|
||||
if (l->l_ld != 0)
|
||||
l->l_ld = (ElfW(Dyn) *) ((ElfW(Addr)) l->l_ld + l->l_addr);
|
||||
l->l_ld = (ElfW(Dyn) *) (l->l_ld_readonly
|
||||
? dl_rx_ptr (l, (elfptr_t) l->l_ld)
|
||||
: dl_rw_ptr (l, (elfptr_t) l->l_ld));
|
||||
|
||||
elf_get_dynamic_info (l, false, false);
|
||||
|
||||
@@ -1314,7 +1316,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
|
||||
}
|
||||
else
|
||||
/* Adjust the PT_PHDR value by the runtime load address. */
|
||||
l->l_phdr = (ElfW(Phdr) *) ((ElfW(Addr)) l->l_phdr + l->l_addr);
|
||||
l->l_phdr = (ElfW(Phdr) *) dl_rx_ptr (l, (ElfW(Addr)) l->l_phdr);
|
||||
|
||||
if (__glibc_unlikely ((stack_flags &~ GL(dl_stack_flags)) & PF_X))
|
||||
{
|
||||
@@ -1369,7 +1371,8 @@ cannot enable executable stack as shared object requires");
|
||||
|
||||
/* Adjust the address of the TLS initialization image. */
|
||||
if (l->l_tls_initimage != NULL)
|
||||
l->l_tls_initimage = (char *) l->l_tls_initimage + l->l_addr;
|
||||
l->l_tls_initimage
|
||||
= (void *) dl_rw_ptr (l, (ElfW(Addr)) l->l_tls_initimage);
|
||||
|
||||
/* Process program headers again after load segments are mapped in
|
||||
case processing requires accessing those segments. Scan program
|
||||
@@ -1402,7 +1405,7 @@ cannot enable executable stack as shared object requires");
|
||||
/* If this is ET_EXEC, we should have loaded it as lt_executable. */
|
||||
assert (type != ET_EXEC || l->l_type == lt_executable);
|
||||
|
||||
l->l_entry += l->l_addr;
|
||||
l->l_entry = dl_rx_ptr (l, l->l_entry);
|
||||
|
||||
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
|
||||
_dl_debug_printf ("\
|
||||
|
||||
+71
-14
@@ -18,15 +18,26 @@
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <dl-load.h>
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
# include <cheri_perms.h>
|
||||
#endif
|
||||
|
||||
/* Allow RWX mprotect later, on CHERI this means RWX capability permission. */
|
||||
#ifdef PROT_MAX
|
||||
# define PROT_MAX_RWX PROT_MAX (PROT_READ | PROT_WRITE | PROT_EXEC)
|
||||
#else
|
||||
# define PROT_MAX_RWX 0
|
||||
#endif
|
||||
|
||||
/* Map a segment and align it properly. */
|
||||
|
||||
static __always_inline ElfW(Addr)
|
||||
static __always_inline elfptr_t
|
||||
_dl_map_segment (const struct loadcmd *c, ElfW(Addr) mappref,
|
||||
const size_t maplength, int fd)
|
||||
{
|
||||
if (__glibc_likely (c->mapalign <= GLRO(dl_pagesize)))
|
||||
return (ElfW(Addr)) __mmap ((void *) mappref, maplength, c->prot,
|
||||
return (elfptr_t) __mmap ((void *) mappref, maplength,
|
||||
c->prot|PROT_MAX_RWX,
|
||||
MAP_COPY|MAP_FILE, fd, c->mapoff);
|
||||
|
||||
/* If the segment alignment > the page size, allocate enough space to
|
||||
@@ -34,16 +45,16 @@ _dl_map_segment (const struct loadcmd *c, ElfW(Addr) mappref,
|
||||
ElfW(Addr) maplen = (maplength >= c->mapalign
|
||||
? (maplength + c->mapalign)
|
||||
: (2 * c->mapalign));
|
||||
ElfW(Addr) map_start = (ElfW(Addr)) __mmap ((void *) mappref, maplen,
|
||||
PROT_NONE,
|
||||
elfptr_t map_start = (elfptr_t) __mmap ((void *) mappref, maplen,
|
||||
PROT_NONE|PROT_MAX_RWX,
|
||||
MAP_ANONYMOUS|MAP_PRIVATE,
|
||||
-1, 0);
|
||||
if (__glibc_unlikely ((void *) map_start == MAP_FAILED))
|
||||
return map_start;
|
||||
|
||||
ElfW(Addr) map_start_aligned = ALIGN_UP (map_start, c->mapalign);
|
||||
map_start_aligned = (ElfW(Addr)) __mmap ((void *) map_start_aligned,
|
||||
maplength, c->prot,
|
||||
elfptr_t map_start_aligned = ALIGN_UP (map_start, c->mapalign);
|
||||
map_start_aligned = (elfptr_t) __mmap ((void *) map_start_aligned,
|
||||
maplength, c->prot|PROT_MAX_RWX,
|
||||
MAP_COPY|MAP_FILE|MAP_FIXED,
|
||||
fd, c->mapoff);
|
||||
if (__glibc_unlikely ((void *) map_start_aligned == MAP_FAILED))
|
||||
@@ -54,7 +65,7 @@ _dl_map_segment (const struct loadcmd *c, ElfW(Addr) mappref,
|
||||
ElfW(Addr) delta = map_start_aligned - map_start;
|
||||
if (delta)
|
||||
__munmap ((void *) map_start, delta);
|
||||
ElfW(Addr) map_end = map_start_aligned + maplength;
|
||||
elfptr_t map_end = map_start + (map_start_aligned - map_start) + maplength;
|
||||
map_end = ALIGN_UP (map_end, GLRO(dl_pagesize));
|
||||
delta = map_start + maplen - map_end;
|
||||
if (delta)
|
||||
@@ -79,6 +90,10 @@ _dl_map_segments (struct link_map *l, int fd,
|
||||
struct link_map *loader)
|
||||
{
|
||||
const struct loadcmd *c = loadcmds;
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
ElfW(Addr) rw_start = -1;
|
||||
ElfW(Addr) rw_end = 0;
|
||||
#endif
|
||||
|
||||
if (__glibc_likely (type == ET_DYN))
|
||||
{
|
||||
@@ -116,7 +131,7 @@ _dl_map_segments (struct link_map *l, int fd,
|
||||
c->mapend))
|
||||
return N_("ELF load command address/offset not page-aligned");
|
||||
if (__glibc_unlikely
|
||||
(__mprotect ((caddr_t) (l->l_addr + c->mapend),
|
||||
(__mprotect ((caddr_t) dl_rx_ptr (l, c->mapend),
|
||||
loadcmds[nloadcmds - 1].mapstart - c->mapend,
|
||||
PROT_NONE) < 0))
|
||||
return DL_MAP_SEGMENTS_ERROR_MPROTECT;
|
||||
@@ -126,6 +141,23 @@ _dl_map_segments (struct link_map *l, int fd,
|
||||
|
||||
goto postmap;
|
||||
}
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
else
|
||||
{
|
||||
/* Need a single capability to cover all load segments. */
|
||||
void *p = __mmap ((void *) c->mapstart, maplength,
|
||||
c->prot|PROT_MAX_RWX,
|
||||
MAP_FIXED|MAP_COPY|MAP_FILE,
|
||||
fd, c->mapoff);
|
||||
if (p == MAP_FAILED)
|
||||
return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT;
|
||||
l->l_map_start = (elfptr_t) p;
|
||||
l->l_map_end = l->l_map_start + maplength;
|
||||
l->l_contiguous = !has_holes;
|
||||
|
||||
goto postmap;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Remember which part of the address space this object uses. */
|
||||
l->l_map_start = c->mapstart + l->l_addr;
|
||||
@@ -134,10 +166,10 @@ _dl_map_segments (struct link_map *l, int fd,
|
||||
|
||||
while (c < &loadcmds[nloadcmds])
|
||||
{
|
||||
if (c->mapend > c->mapstart
|
||||
if (c->dataend > c->mapstart
|
||||
/* Map the segment contents from the file. */
|
||||
&& (__mmap ((void *) (l->l_addr + c->mapstart),
|
||||
c->mapend - c->mapstart, c->prot,
|
||||
&& (__mmap ((void *) dl_rx_ptr (l, c->mapstart),
|
||||
c->dataend - c->mapstart, c->prot,
|
||||
MAP_FIXED|MAP_COPY|MAP_FILE,
|
||||
fd, c->mapoff)
|
||||
== MAP_FAILED))
|
||||
@@ -146,13 +178,28 @@ _dl_map_segments (struct link_map *l, int fd,
|
||||
postmap:
|
||||
_dl_postprocess_loadcmd (l, header, c);
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
if (c->prot & PROT_WRITE)
|
||||
{
|
||||
if (l->l_rw_count >= DL_MAX_RW_COUNT)
|
||||
return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT; // TODO: right error code
|
||||
if (c->mapstart < rw_start)
|
||||
rw_start = c->mapstart;
|
||||
if (c->allocend > rw_end)
|
||||
rw_end = c->allocend;
|
||||
l->l_rw_range[l->l_rw_count].start = l->l_addr + c->mapstart;
|
||||
l->l_rw_range[l->l_rw_count].end = l->l_addr + c->allocend;
|
||||
l->l_rw_count++;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (c->allocend > c->dataend)
|
||||
{
|
||||
/* Extra zero pages should appear at the end of this segment,
|
||||
after the data mapped from the file. */
|
||||
ElfW(Addr) zero, zeroend, zeropage;
|
||||
elfptr_t zero, zeroend, zeropage;
|
||||
|
||||
zero = l->l_addr + c->dataend;
|
||||
zero = dl_rx_ptr (l, c->dataend);
|
||||
zeroend = l->l_addr + c->allocend;
|
||||
zeropage = ((zero + GLRO(dl_pagesize) - 1)
|
||||
& ~(GLRO(dl_pagesize) - 1));
|
||||
@@ -194,6 +241,16 @@ _dl_map_segments (struct link_map *l, int fd,
|
||||
++c;
|
||||
}
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
if (l->l_rw_count > 0)
|
||||
{
|
||||
l->l_rw_start = __builtin_cheri_address_set (l->l_map_start, l->l_addr + rw_start);
|
||||
l->l_rw_start = __builtin_cheri_bounds_set (l->l_rw_start, rw_end - rw_start);
|
||||
l->l_rw_start = __builtin_cheri_perms_and (l->l_rw_start, CAP_PERM_MASK_RW);
|
||||
}
|
||||
l->l_map_start = __builtin_cheri_perms_and (l->l_map_start, CAP_PERM_MASK_RX);
|
||||
#endif
|
||||
|
||||
/* Notify ELF_PREFERRED_ADDRESS that we have to load this one
|
||||
fixed. */
|
||||
ELF_FIXED_ADDRESS (loader, c->mapstart);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
# pragma GCC visibility push(hidden)
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <ldsodefs.h>
|
||||
#include <malloc/malloc-internal.h>
|
||||
@@ -33,6 +34,7 @@ static void *alloc_ptr, *alloc_end, *alloc_last_block;
|
||||
void *
|
||||
__minimal_malloc (size_t n)
|
||||
{
|
||||
#ifndef __CHERI_PURE_CAPABILITY__
|
||||
if (alloc_end == 0)
|
||||
{
|
||||
/* Consume any unused space in the last page of our data segment. */
|
||||
@@ -42,9 +44,10 @@ __minimal_malloc (size_t n)
|
||||
+ GLRO(dl_pagesize) - 1)
|
||||
& ~(GLRO(dl_pagesize) - 1));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Make sure the allocation pointer is ideally aligned. */
|
||||
alloc_ptr = (void *) 0 + (((alloc_ptr - (void *) 0) + MALLOC_ALIGNMENT - 1)
|
||||
alloc_ptr = (void *)(((uintptr_t)alloc_ptr + (MALLOC_ALIGNMENT - 1))
|
||||
& ~(MALLOC_ALIGNMENT - 1));
|
||||
|
||||
if (alloc_ptr + n >= alloc_end || n >= -(uintptr_t) alloc_ptr)
|
||||
|
||||
+5
-2
@@ -163,8 +163,11 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg)
|
||||
/* We use alloca() to allocate the buffer with the most
|
||||
pessimistic guess for the size. Using alloca() allows
|
||||
having more than one integer formatting in a call. */
|
||||
char *buf = (char *) alloca (1 + 3 * sizeof (unsigned long int));
|
||||
char *endp = &buf[1 + 3 * sizeof (unsigned long int)];
|
||||
int size = 1 + 3 * sizeof (unsigned long int);
|
||||
if (width + 1 > size)
|
||||
size = width + 1;
|
||||
char *buf = (char *) alloca (size);
|
||||
char *endp = &buf[size];
|
||||
char *cp = _itoa (num, endp, *fmt == 'x' ? 16 : 10, 0);
|
||||
|
||||
/* Pad to the width the user specified. */
|
||||
|
||||
@@ -182,6 +182,9 @@ static unsigned int log_hashfraction;
|
||||
void
|
||||
_dl_start_profile (void)
|
||||
{
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
__libc_fatal ("Profiling is not supported on capability architectures.");
|
||||
#else
|
||||
char *filename;
|
||||
int fd;
|
||||
struct __stat64_t64 st;
|
||||
@@ -482,6 +485,7 @@ _dl_start_profile (void)
|
||||
|
||||
/* Turn on profiling. */
|
||||
running = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-2
@@ -353,8 +353,7 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
|
||||
void
|
||||
_dl_protect_relro (struct link_map *l)
|
||||
{
|
||||
ElfW(Addr) start = ALIGN_DOWN((l->l_addr
|
||||
+ l->l_relro_addr),
|
||||
elfptr_t start = ALIGN_DOWN(dl_rx_ptr (l, l->l_relro_addr),
|
||||
GLRO(dl_pagesize));
|
||||
ElfW(Addr) end = ALIGN_DOWN((l->l_addr
|
||||
+ l->l_relro_addr
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ _dl_fixup (
|
||||
+ reloc_offset (pltgot, reloc_arg));
|
||||
const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
|
||||
const ElfW(Sym) *refsym = sym;
|
||||
void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
|
||||
void *const rel_addr = (void *) dl_rw_ptr (l, reloc->r_offset);
|
||||
lookup_t result;
|
||||
DL_FIXUP_VALUE_TYPE value;
|
||||
|
||||
|
||||
@@ -255,6 +255,13 @@ _dl_aux_init (ElfW(auxv_t) *av)
|
||||
for (int i = 0; i < array_length (auxv_values); ++i)
|
||||
auxv_values[i] = 0;
|
||||
_dl_parse_auxv (av, auxv_values);
|
||||
|
||||
# ifdef __CHERI_PURE_CAPABILITY__
|
||||
_dl_main_map.l_map_start = auxv_values[AT_CHERI_EXEC_RX_CAP];
|
||||
_dl_main_map.l_map_start = __builtin_cheri_perms_and (_dl_main_map.l_map_start, CAP_PERM_MASK_RX);
|
||||
_dl_main_map.l_rw_start = auxv_values[AT_CHERI_EXEC_RW_CAP];
|
||||
_dl_main_map.l_rw_start = __builtin_cheri_perms_and (_dl_main_map.l_rw_start, CAP_PERM_MASK_RW);
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ _dl_sym_post (lookup_t result, const ElfW(Sym) *ref, void *value,
|
||||
if (__glibc_unlikely (ELFW(ST_TYPE) (ref->st_info) == STT_GNU_IFUNC))
|
||||
{
|
||||
DL_FIXUP_VALUE_TYPE fixup
|
||||
= DL_FIXUP_MAKE_VALUE (result, (ElfW(Addr)) value);
|
||||
= DL_FIXUP_MAKE_VALUE (result, (elfptr_t) value);
|
||||
fixup = elf_ifunc_invoke (DL_FIXUP_VALUE_ADDR (fixup));
|
||||
value = (void *) DL_FIXUP_VALUE_CODE_ADDR (fixup);
|
||||
}
|
||||
|
||||
@@ -49,6 +49,10 @@ _dl_tls_symaddr (struct link_map *map, const ElfW(Sym) *ref)
|
||||
{
|
||||
.ti_module = map->l_tls_modid,
|
||||
.ti_offset = ref->st_value
|
||||
# ifdef __CHERI_PURE_CAPABILITY__
|
||||
,
|
||||
.ti_size = ref->st_size
|
||||
# endif
|
||||
};
|
||||
|
||||
return __TLS_GET_ADDR (&tmp);
|
||||
|
||||
@@ -62,7 +62,11 @@
|
||||
observed PT_GNU_TLS sizes across all architectures. Some
|
||||
architectures have lower values due to differences in type sizes
|
||||
and link editor capabilities. */
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
#define LIBC_IE_TLS 256
|
||||
#else
|
||||
#define LIBC_IE_TLS 144
|
||||
#endif
|
||||
|
||||
/* Size of initial-exec TLS in libraries other than libc.so.
|
||||
This should be large enough to cover runtime libraries of the
|
||||
@@ -87,7 +91,11 @@ tls_static_surplus (int nns, int opt_tls)
|
||||
the computation of dl_tls_static_surplus in
|
||||
_dl_tls_static_surplus_init yields the historic value 1664, for
|
||||
backwards compatibility. */
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
#define LEGACY_TLS 0
|
||||
#else
|
||||
#define LEGACY_TLS (1664 - tls_static_surplus (DEFAULT_NNS, OPTIONAL_TLS))
|
||||
#endif
|
||||
|
||||
/* Calculate the size of the static TLS surplus, when the given
|
||||
number of audit modules are loaded. Must be called after the
|
||||
|
||||
@@ -159,6 +159,13 @@ glibc {
|
||||
maxval: 255
|
||||
security_level: SXID_IGNORE
|
||||
}
|
||||
cap_narrowing {
|
||||
type: INT_32
|
||||
minval: 0
|
||||
maxval: 1
|
||||
default: 1
|
||||
security_level: SXID_IGNORE
|
||||
}
|
||||
}
|
||||
|
||||
rtld {
|
||||
|
||||
+5
-5
@@ -86,7 +86,7 @@ checking for version `%s' in file %s [%lu] required by file %s [%lu]\n",
|
||||
def_offset = map->l_info[VERSYMIDX (DT_VERDEF)]->d_un.d_ptr;
|
||||
assert (def_offset != 0);
|
||||
|
||||
def = (ElfW(Verdef) *) ((char *) map->l_addr + def_offset);
|
||||
def = (ElfW(Verdef) *) dl_rx_ptr (map, def_offset);
|
||||
while (1)
|
||||
{
|
||||
/* Currently the version number of the definition entry is 1.
|
||||
@@ -177,7 +177,7 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
|
||||
if (dyn != NULL)
|
||||
{
|
||||
/* This file requires special versions from its dependencies. */
|
||||
ElfW(Verneed) *ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
|
||||
ElfW(Verneed) *ent = (ElfW(Verneed) *) dl_rx_ptr (map, dyn->d_un.d_ptr);
|
||||
|
||||
/* Currently the version number of the needed entry is 1.
|
||||
Make sure all we see is this version. */
|
||||
@@ -257,7 +257,7 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
|
||||
if (def != NULL)
|
||||
{
|
||||
ElfW(Verdef) *ent;
|
||||
ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
|
||||
ent = (ElfW(Verdef) *) dl_rx_ptr (map, def->d_un.d_ptr);
|
||||
while (1)
|
||||
{
|
||||
if ((unsigned int) (ent->vd_ndx & 0x7fff) > ndx_high)
|
||||
@@ -296,7 +296,7 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
|
||||
if (dyn != NULL)
|
||||
{
|
||||
ElfW(Verneed) *ent;
|
||||
ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
|
||||
ent = (ElfW(Verneed) *) dl_rx_ptr (map, dyn->d_un.d_ptr);
|
||||
while (1)
|
||||
{
|
||||
ElfW(Vernaux) *aux;
|
||||
@@ -334,7 +334,7 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
|
||||
if (def != NULL)
|
||||
{
|
||||
ElfW(Verdef) *ent;
|
||||
ent = (ElfW(Verdef) *) (map->l_addr + def->d_un.d_ptr);
|
||||
ent = (ElfW(Verdef) *) dl_rx_ptr (map, def->d_un.d_ptr);
|
||||
while (1)
|
||||
{
|
||||
ElfW(Verdaux) *aux;
|
||||
|
||||
+6
-6
@@ -41,7 +41,7 @@
|
||||
|
||||
static inline void __attribute__ ((always_inline))
|
||||
elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
ElfW(Addr) reladdr, ElfW(Addr) relsize,
|
||||
elfptr_t reladdr, ElfW(Addr) relsize,
|
||||
__typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative,
|
||||
int lazy, int skip_ifunc)
|
||||
{
|
||||
@@ -62,7 +62,7 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
{
|
||||
ElfW (Half) ndx = version[ELFW (R_SYM) (r->r_info)] & 0x7fff;
|
||||
const ElfW (Sym) *sym = &symtab[ELFW (R_SYM) (r->r_info)];
|
||||
void *const r_addr_arg = (void *) (l_addr + r->r_offset);
|
||||
void *const r_addr_arg = (void *) dl_rw_ptr (map, r->r_offset);
|
||||
const struct r_found_version *rversion = &map->l_versions[ndx];
|
||||
|
||||
elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg, skip_ifunc);
|
||||
@@ -132,7 +132,7 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
{
|
||||
ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
|
||||
const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (r->r_info)];
|
||||
void *const r_addr_arg = (void *) (l_addr + r->r_offset);
|
||||
void *const r_addr_arg = (void *) dl_rw_ptr (map, r->r_offset);
|
||||
const struct r_found_version *rversion = &map->l_versions[ndx];
|
||||
#if defined ELF_MACHINE_IRELATIVE
|
||||
if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
|
||||
@@ -169,7 +169,7 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
elf_machine_rel (map, scope, r2,
|
||||
&symtab[ELFW(R_SYM) (r2->r_info)],
|
||||
&map->l_versions[ndx],
|
||||
(void *) (l_addr + r2->r_offset),
|
||||
(void *) dl_rw_ptr (map, r2->r_offset),
|
||||
skip_ifunc);
|
||||
}
|
||||
#endif
|
||||
@@ -179,7 +179,7 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
for (; r < end; ++r)
|
||||
{
|
||||
const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (r->r_info)];
|
||||
void *const r_addr_arg = (void *) (l_addr + r->r_offset);
|
||||
void *const r_addr_arg = (void *) dl_rw_ptr (map, r->r_offset);
|
||||
# ifdef ELF_MACHINE_IRELATIVE
|
||||
if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
|
||||
{
|
||||
@@ -210,7 +210,7 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
for (; r2 <= end2; ++r2)
|
||||
if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
|
||||
elf_machine_rel (map, scope, r2, &symtab[ELFW(R_SYM) (r2->r_info)],
|
||||
NULL, (void *) (l_addr + r2->r_offset),
|
||||
NULL, (void *) dl_rw_ptr (map, r2->r_offset),
|
||||
skip_ifunc);
|
||||
# endif
|
||||
}
|
||||
|
||||
+7
-2
@@ -46,9 +46,14 @@ elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
|
||||
const ElfW(Rela) *reloc, const ElfW(Sym) *sym,
|
||||
const struct r_found_version *version, void *const reloc_addr,
|
||||
int skip_ifunc);
|
||||
# ifdef __CHERI_PURE_CAPABILITY__
|
||||
static inline void __attribute__((always_inline))
|
||||
elf_machine_rela_relative (struct link_map *map, const ElfW(Rela) *reloc);
|
||||
# else
|
||||
static inline void __attribute__((always_inline))
|
||||
elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
|
||||
void *const reloc_addr);
|
||||
# endif
|
||||
# endif
|
||||
# if ELF_MACHINE_NO_RELA || defined ELF_MACHINE_PLT_REL
|
||||
static inline void __attribute__((always_inline))
|
||||
@@ -80,7 +85,7 @@ elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
|
||||
# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, scope, do_lazy, skip_ifunc, test_rel) \
|
||||
do { \
|
||||
struct { ElfW(Addr) start, size; \
|
||||
struct { elfptr_t start; ElfW(Addr) size; \
|
||||
__typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative; int lazy; } \
|
||||
ranges[2] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }; \
|
||||
\
|
||||
@@ -97,7 +102,7 @@ elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
if ((map)->l_info[DT_PLTREL] \
|
||||
&& (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
|
||||
{ \
|
||||
ElfW(Addr) start = D_PTR ((map), l_info[DT_JMPREL]); \
|
||||
elfptr_t start = D_PTR ((map), l_info[DT_JMPREL]); \
|
||||
ElfW(Addr) size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
|
||||
\
|
||||
if (ranges[0].start == 0) \
|
||||
|
||||
@@ -1159,6 +1159,14 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
#if defined __CHERI_PURE_CAPABILITY__
|
||||
uint64_t a_type;
|
||||
uint64_t __pad;
|
||||
union
|
||||
{
|
||||
__uintcap_t a_val;
|
||||
} a_un;
|
||||
#else
|
||||
uint64_t a_type; /* Entry type */
|
||||
union
|
||||
{
|
||||
@@ -1167,6 +1175,7 @@ typedef struct
|
||||
though, since it does not work when using 32-bit definitions
|
||||
on 64-bit platforms and vice versa. */
|
||||
} a_un;
|
||||
#endif
|
||||
} Elf64_auxv_t;
|
||||
|
||||
/* Legal values for a_type (entry type). */
|
||||
@@ -1243,6 +1252,18 @@ typedef struct
|
||||
|
||||
#define AT_MINSIGSTKSZ 51 /* Stack needed for signal delivery */
|
||||
|
||||
#define AT_CHERI_EXEC_RW_CAP 60
|
||||
#define AT_CHERI_EXEC_RX_CAP 61
|
||||
#define AT_CHERI_INTERP_RW_CAP 62
|
||||
#define AT_CHERI_INTERP_RX_CAP 63
|
||||
#define AT_CHERI_STACK_CAP 64
|
||||
#define AT_CHERI_SEAL_CAP 65
|
||||
#define AT_CHERI_CID_CAP 66
|
||||
#define AT_ARGC 80
|
||||
#define AT_ARGV 81
|
||||
#define AT_ENVC 82
|
||||
#define AT_ENVP 83
|
||||
|
||||
/* Note section contents. Each entry in the note section begins with
|
||||
a header of a fixed form. */
|
||||
|
||||
@@ -2906,6 +2927,9 @@ enum
|
||||
/* MTE memory tag segment type. */
|
||||
#define PT_AARCH64_MEMTAG_MTE (PT_LOPROC + 2)
|
||||
|
||||
/* Processor specific flags for the ELF header e_flags field. */
|
||||
#define EF_AARCH64_CHERI_PURECAP 0x00010000
|
||||
|
||||
/* AArch64 specific values for the Dyn d_tag field. */
|
||||
#define DT_AARCH64_BTI_PLT (DT_LOPROC + 1)
|
||||
#define DT_AARCH64_PAC_PLT (DT_LOPROC + 3)
|
||||
@@ -2915,6 +2939,27 @@ enum
|
||||
/* AArch64 specific values for the st_other field. */
|
||||
#define STO_AARCH64_VARIANT_PCS 0x80
|
||||
|
||||
/* Morello relocs. */
|
||||
#define R_MORELLO_TSTBR14 57344
|
||||
#define R_MORELLO_CONDBR19 57345
|
||||
#define R_MORELLO_JUMP26 57346
|
||||
#define R_MORELLO_CALL26 57347
|
||||
#define R_MORELLO_LD_PREL_LO17 57348
|
||||
#define R_MORELLO_ADR_PREL_PG_HI20 57349
|
||||
#define R_MORELLO_ADR_PREL_PG_HI20_NC 57350
|
||||
#define R_MORELLO_ADR_GOT_PAGE 57351
|
||||
#define R_MORELLO_LD128_GOT_LO12_NC 57352
|
||||
#define R_MORELLO_TLSDESC_ADR_PAGE20 57600
|
||||
#define R_MORELLO_TLSDESC_LD128_LO12 57601
|
||||
#define R_MORELLO_TLSDESC_CALL 57602
|
||||
#define R_MORELLO_CAPINIT 59392
|
||||
#define R_MORELLO_GLOB_DAT 59393
|
||||
#define R_MORELLO_JUMP_SLOT 59394
|
||||
#define R_MORELLO_RELATIVE 59395
|
||||
#define R_MORELLO_IRELATIVE 59396
|
||||
#define R_MORELLO_TLSDESC 59397
|
||||
#define R_MORELLO_TPREL128 59398
|
||||
|
||||
/* ARM relocs. */
|
||||
|
||||
#define R_ARM_NONE 0 /* No reloc */
|
||||
|
||||
+7
-1
@@ -34,6 +34,12 @@
|
||||
#include <bits/elfclass.h> /* Defines __ELF_NATIVE_CLASS. */
|
||||
#include <bits/link.h>
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
typedef uintptr_t elfptr_t;
|
||||
#else
|
||||
typedef ElfW(Addr) elfptr_t;
|
||||
#endif
|
||||
|
||||
/* The legacy rendezvous structure used by the run-time dynamic linker to
|
||||
communicate details of shared object loading to the debugger. */
|
||||
|
||||
@@ -154,7 +160,7 @@ enum
|
||||
|
||||
struct dl_phdr_info
|
||||
{
|
||||
ElfW(Addr) dlpi_addr;
|
||||
elfptr_t dlpi_addr;
|
||||
const char *dlpi_name;
|
||||
const ElfW(Phdr) *dlpi_phdr;
|
||||
ElfW(Half) dlpi_phnum;
|
||||
|
||||
+43
-15
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <dl-r_debug.h>
|
||||
|
||||
#ifndef __CHERI_PURE_CAPABILITY__
|
||||
struct E(link_map)
|
||||
{
|
||||
EW(Addr) l_addr;
|
||||
@@ -35,6 +36,48 @@ struct E(link_map)
|
||||
Lmid_t l_ns;
|
||||
EW(Addr) l_libname;
|
||||
};
|
||||
|
||||
struct E(libname_list)
|
||||
{
|
||||
EW(Addr) name;
|
||||
EW(Addr) next;
|
||||
};
|
||||
|
||||
struct E(r_debug)
|
||||
{
|
||||
int r_version;
|
||||
# if CLASS == 64
|
||||
int pad;
|
||||
# endif
|
||||
EW(Addr) r_map;
|
||||
};
|
||||
#else
|
||||
struct E(link_map)
|
||||
{
|
||||
uintptr_t l_addr;
|
||||
uintptr_t l_name;
|
||||
uintptr_t l_ld;
|
||||
uintptr_t l_next;
|
||||
uintptr_t l_prev;
|
||||
uintptr_t l_real;
|
||||
Lmid_t l_ns;
|
||||
uintptr_t l_libname;
|
||||
};
|
||||
|
||||
struct E(libname_list)
|
||||
{
|
||||
uintptr_t name;
|
||||
uintptr_t next;
|
||||
};
|
||||
|
||||
struct E(r_debug)
|
||||
{
|
||||
int r_version;
|
||||
int pad;
|
||||
uintptr_t r_map;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if CLASS == __ELF_NATIVE_CLASS
|
||||
_Static_assert (offsetof (struct link_map, l_addr)
|
||||
== offsetof (struct E(link_map), l_addr), "l_addr");
|
||||
@@ -44,27 +87,12 @@ _Static_assert (offsetof (struct link_map, l_next)
|
||||
== offsetof (struct E(link_map), l_next), "l_next");
|
||||
#endif
|
||||
|
||||
|
||||
struct E(libname_list)
|
||||
{
|
||||
EW(Addr) name;
|
||||
EW(Addr) next;
|
||||
};
|
||||
#if CLASS == __ELF_NATIVE_CLASS
|
||||
_Static_assert (offsetof (struct libname_list, name)
|
||||
== offsetof (struct E(libname_list), name), "name");
|
||||
_Static_assert (offsetof (struct libname_list, next)
|
||||
== offsetof (struct E(libname_list), next), "next");
|
||||
#endif
|
||||
|
||||
struct E(r_debug)
|
||||
{
|
||||
int r_version;
|
||||
#if CLASS == 64
|
||||
int pad;
|
||||
#endif
|
||||
EW(Addr) r_map;
|
||||
};
|
||||
#if CLASS == __ELF_NATIVE_CLASS
|
||||
_Static_assert (offsetof (struct r_debug, r_version)
|
||||
== offsetof (struct E(r_debug), r_version), "r_version");
|
||||
|
||||
+70
-16
@@ -384,7 +384,7 @@ extern struct rtld_global_ro _rtld_local_ro
|
||||
|
||||
|
||||
static void dl_main (const ElfW(Phdr) *phdr, ElfW(Word) phnum,
|
||||
ElfW(Addr) *user_entry, ElfW(auxv_t) *auxv);
|
||||
elfptr_t *user_entry, ElfW(auxv_t) *auxv);
|
||||
|
||||
/* These two variables cannot be moved into .data.rel.ro. */
|
||||
static struct libname_list _dl_rtld_libname;
|
||||
@@ -416,15 +416,15 @@ DL_SYSINFO_IMPLEMENTATION
|
||||
#endif
|
||||
|
||||
#ifdef DONT_USE_BOOTSTRAP_MAP
|
||||
static ElfW(Addr) _dl_start_final (void *arg);
|
||||
static elfptr_t _dl_start_final (void *arg);
|
||||
#else
|
||||
struct dl_start_final_info
|
||||
{
|
||||
struct link_map l;
|
||||
RTLD_TIMING_VAR (start_time);
|
||||
};
|
||||
static ElfW(Addr) _dl_start_final (void *arg,
|
||||
struct dl_start_final_info *info);
|
||||
static elfptr_t _dl_start_final (void *arg,
|
||||
struct dl_start_final_info *info);
|
||||
#endif
|
||||
|
||||
/* These are defined magically by the linker. */
|
||||
@@ -446,14 +446,14 @@ RTLD_START
|
||||
this function is not inlined (see below). */
|
||||
|
||||
#ifdef DONT_USE_BOOTSTRAP_MAP
|
||||
static inline ElfW(Addr) __attribute__ ((always_inline))
|
||||
static inline elfptr_t __attribute__ ((always_inline))
|
||||
_dl_start_final (void *arg)
|
||||
#else
|
||||
static ElfW(Addr) __attribute__ ((noinline))
|
||||
static elfptr_t __attribute__ ((noinline))
|
||||
_dl_start_final (void *arg, struct dl_start_final_info *info)
|
||||
#endif
|
||||
{
|
||||
ElfW(Addr) start_addr;
|
||||
elfptr_t start_addr;
|
||||
|
||||
/* Do not use an initializer for these members because it would
|
||||
intefere with __rtld_static_init. */
|
||||
@@ -474,10 +474,19 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
|
||||
sizeof GL(dl_rtld_map).l_info);
|
||||
GL(dl_rtld_map).l_mach = info->l.l_mach;
|
||||
GL(dl_rtld_map).l_relocated = 1;
|
||||
# ifdef __CHERI_PURE_CAPABILITY__
|
||||
GL(dl_rtld_map).l_map_start = info->l.l_map_start;
|
||||
GL(dl_rtld_map).l_rw_start = info->l.l_rw_start;
|
||||
GL(dl_rtld_map).l_rw_count = info->l.l_rw_count;
|
||||
for (int i = 0; i < info->l.l_rw_count; i++)
|
||||
GL(dl_rtld_map).l_rw_range[i] = info->l.l_rw_range[i];
|
||||
# endif
|
||||
#endif
|
||||
_dl_setup_hash (&GL(dl_rtld_map));
|
||||
GL(dl_rtld_map).l_real = &GL(dl_rtld_map);
|
||||
#ifndef __CHERI_PURE_CAPABILITY__
|
||||
GL(dl_rtld_map).l_map_start = (ElfW(Addr)) &__ehdr_start;
|
||||
#endif
|
||||
GL(dl_rtld_map).l_map_end = (ElfW(Addr)) _end;
|
||||
GL(dl_rtld_map).l_text_end = (ElfW(Addr)) _etext;
|
||||
/* Copy the TLS related data if necessary. */
|
||||
@@ -515,7 +524,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
|
||||
# define bootstrap_map info.l
|
||||
#endif
|
||||
|
||||
static ElfW(Addr) __attribute_used__
|
||||
static elfptr_t __attribute_used__
|
||||
_dl_start (void *arg)
|
||||
{
|
||||
#ifdef DONT_USE_BOOTSTRAP_MAP
|
||||
@@ -542,11 +551,16 @@ _dl_start (void *arg)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
elf_machine_rtld_base_setup (&bootstrap_map, arg);
|
||||
bootstrap_map.l_ld = elf_machine_runtime_dynamic ();
|
||||
#else
|
||||
/* Figure out the run-time load address of the dynamic linker itself. */
|
||||
bootstrap_map.l_addr = elf_machine_load_address ();
|
||||
|
||||
/* Read our own dynamic section and fill in the info array. */
|
||||
bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic ();
|
||||
#endif
|
||||
bootstrap_map.l_ld_readonly = DL_RO_DYN_SECTION;
|
||||
elf_get_dynamic_info (&bootstrap_map, true, false);
|
||||
|
||||
@@ -708,8 +722,7 @@ match_version (const char *string, struct link_map *map)
|
||||
/* The file has no symbol versioning. */
|
||||
return 0;
|
||||
|
||||
def = (ElfW(Verdef) *) ((char *) map->l_addr
|
||||
+ map->l_info[VERDEFTAG]->d_un.d_ptr);
|
||||
def = (ElfW(Verdef) *) dl_rx_ptr (map, map->l_info[VERDEFTAG]->d_un.d_ptr);
|
||||
while (1)
|
||||
{
|
||||
ElfW(Verdaux) *aux = (ElfW(Verdaux) *) ((char *) def + def->vd_aux);
|
||||
@@ -1125,8 +1138,13 @@ rtld_setup_main_map (struct link_map *main_map)
|
||||
|
||||
main_map->l_map_end = 0;
|
||||
main_map->l_text_end = 0;
|
||||
#ifndef __CHERI_PURE_CAPABILITY__
|
||||
/* Perhaps the executable has no PT_LOAD header entries at all. */
|
||||
main_map->l_map_start = ~0;
|
||||
#else
|
||||
/* May be computed already when exe is loaded by ld.so. */
|
||||
main_map->l_rw_count = 0;
|
||||
#endif
|
||||
/* And it was opened directly. */
|
||||
++main_map->l_direct_opencount;
|
||||
main_map->l_contiguous = 1;
|
||||
@@ -1157,8 +1175,10 @@ rtld_setup_main_map (struct link_map *main_map)
|
||||
case PT_DYNAMIC:
|
||||
/* This tells us where to find the dynamic section,
|
||||
which tells us everything we need to do. */
|
||||
main_map->l_ld = (void *) main_map->l_addr + ph->p_vaddr;
|
||||
main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
|
||||
main_map->l_ld = (void *) (main_map->l_ld_readonly
|
||||
? dl_rx_ptr (main_map, ph->p_vaddr)
|
||||
: dl_rw_ptr (main_map, ph->p_vaddr));
|
||||
break;
|
||||
case PT_INTERP:
|
||||
/* This "interpreter segment" was used by the program loader to
|
||||
@@ -1167,8 +1187,8 @@ rtld_setup_main_map (struct link_map *main_map)
|
||||
dlopen call or DT_NEEDED entry, for something that wants to link
|
||||
against the dynamic linker as a shared library, will know that
|
||||
the shared object is already loaded. */
|
||||
_dl_rtld_libname.name = ((const char *) main_map->l_addr
|
||||
+ ph->p_vaddr);
|
||||
_dl_rtld_libname.name = (const char *) dl_rx_ptr (main_map,
|
||||
ph->p_vaddr);
|
||||
/* _dl_rtld_libname.next = NULL; Already zero. */
|
||||
GL(dl_rtld_map).l_libname = &_dl_rtld_libname;
|
||||
|
||||
@@ -1205,8 +1225,10 @@ rtld_setup_main_map (struct link_map *main_map)
|
||||
/* Remember where the main program starts in memory. */
|
||||
mapstart = (main_map->l_addr
|
||||
+ (ph->p_vaddr & ~(GLRO(dl_pagesize) - 1)));
|
||||
#ifndef __CHERI_PURE_CAPABILITY__
|
||||
if (main_map->l_map_start > mapstart)
|
||||
main_map->l_map_start = mapstart;
|
||||
#endif
|
||||
|
||||
if (main_map->l_contiguous && expected_load_address != 0
|
||||
&& expected_load_address != mapstart)
|
||||
@@ -1223,6 +1245,15 @@ rtld_setup_main_map (struct link_map *main_map)
|
||||
segment. */
|
||||
expected_load_address = ((allocend + GLRO(dl_pagesize) - 1)
|
||||
& ~(GLRO(dl_pagesize) - 1));
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
if (ph->p_flags & PF_W)
|
||||
{
|
||||
assert (main_map->l_rw_count < DL_MAX_RW_COUNT);
|
||||
main_map->l_rw_range[main_map->l_rw_count].start = mapstart;
|
||||
main_map->l_rw_range[main_map->l_rw_count].end = allocend;
|
||||
main_map->l_rw_count++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1274,7 +1305,7 @@ rtld_setup_main_map (struct link_map *main_map)
|
||||
the executable is actually an ET_DYN object. */
|
||||
if (main_map->l_tls_initimage != NULL)
|
||||
main_map->l_tls_initimage
|
||||
= (char *) main_map->l_tls_initimage + main_map->l_addr;
|
||||
= (void *) dl_rx_ptr (main_map, (ElfW(Addr)) main_map->l_tls_initimage);
|
||||
if (! main_map->l_map_end)
|
||||
main_map->l_map_end = ~0;
|
||||
if (! main_map->l_text_end)
|
||||
@@ -1352,7 +1383,7 @@ _dl_start_args_adjust (int skip_args)
|
||||
static void
|
||||
dl_main (const ElfW(Phdr) *phdr,
|
||||
ElfW(Word) phnum,
|
||||
ElfW(Addr) *user_entry,
|
||||
elfptr_t *user_entry,
|
||||
ElfW(auxv_t) *auxv)
|
||||
{
|
||||
struct link_map *main_map;
|
||||
@@ -1635,6 +1666,14 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
case AT_EXECFN:
|
||||
av->a_un.a_val = (uintptr_t) _dl_argv[0];
|
||||
break;
|
||||
# ifdef __CHERI_PURE_CAPABILITY__
|
||||
case AT_CHERI_EXEC_RX_CAP:
|
||||
av->a_un.a_val = main_map->l_map_start;
|
||||
break;
|
||||
case AT_CHERI_EXEC_RW_CAP:
|
||||
av->a_un.a_val = main_map->l_rw_start;
|
||||
break;
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1678,6 +1717,21 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
|
||||
/* We delay initializing the path structure until we got the dynamic
|
||||
information for the program. */
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
for (ElfW(auxv_t) *av = auxv; av->a_type != AT_NULL; av++)
|
||||
switch (av->a_type)
|
||||
{
|
||||
case AT_CHERI_EXEC_RX_CAP:
|
||||
main_map->l_map_start = av->a_un.a_val;
|
||||
main_map->l_map_start = __builtin_cheri_perms_and (main_map->l_map_start, CAP_PERM_MASK_RX);
|
||||
break;
|
||||
case AT_CHERI_EXEC_RW_CAP:
|
||||
main_map->l_rw_start = av->a_un.a_val;
|
||||
main_map->l_rw_start = __builtin_cheri_perms_and (main_map->l_rw_start, CAP_PERM_MASK_RW);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool has_interp = rtld_setup_main_map (main_map);
|
||||
@@ -2194,7 +2248,7 @@ dl_main (const ElfW(Phdr) *phdr,
|
||||
continue;
|
||||
|
||||
strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
|
||||
ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr);
|
||||
ent = (ElfW(Verneed) *) dl_rx_ptr (map, dyn->d_un.d_ptr);
|
||||
|
||||
if (first)
|
||||
{
|
||||
|
||||
@@ -27,7 +27,11 @@ static int
|
||||
do_test (int argc, char *argv[])
|
||||
{
|
||||
errno = 0;
|
||||
#ifndef __CHERI_PURE_CAPABILITY__
|
||||
const char *execfn = (const char *) getauxval (AT_NULL);
|
||||
#else
|
||||
const char *execfn = (const char *) getauxptr (AT_NULL);
|
||||
#endif
|
||||
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
@@ -43,7 +47,11 @@ do_test (int argc, char *argv[])
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
#ifndef __CHERI_PURE_CAPABILITY__
|
||||
execfn = (const char *) getauxval (AT_EXECFN);
|
||||
#else
|
||||
execfn = (const char *) getauxptr (AT_EXECFN);
|
||||
#endif
|
||||
|
||||
if (execfn == NULL)
|
||||
{
|
||||
|
||||
@@ -30,7 +30,7 @@ static int
|
||||
callback (struct dl_phdr_info *info, size_t size, void *ptr)
|
||||
{
|
||||
static int last_adds = 0, last_subs = 0;
|
||||
intptr_t cmd = (intptr_t) ptr;
|
||||
unsigned long cmd = (intptr_t) ptr;
|
||||
|
||||
printf (" size = %Zu\n", size);
|
||||
if (size < (offsetof (struct dl_phdr_info, dlpi_subs)
|
||||
|
||||
+2
-2
@@ -264,7 +264,7 @@ do_test_dependency (void)
|
||||
xdlclose (moddep);
|
||||
}
|
||||
|
||||
for (int n = 1; n <= nmods; n++)
|
||||
for (int n = 1; n < nmods; n++)
|
||||
if (mods[n] != 0)
|
||||
unload_mod (n);
|
||||
}
|
||||
@@ -342,7 +342,7 @@ do_test_invalid_dependency (bool bind_now)
|
||||
xdlclose (moddep);
|
||||
}
|
||||
|
||||
for (int n = 1; n <= nmods; n++)
|
||||
for (int n = 1; n < nmods; n++)
|
||||
if (mods[n] != 0)
|
||||
unload_mod (n);
|
||||
}
|
||||
|
||||
@@ -31,13 +31,13 @@
|
||||
static void
|
||||
activate_test_gconv_modules (void)
|
||||
{
|
||||
unsigned long ptr = getauxval (AT_EXECFN);
|
||||
if (ptr == 0)
|
||||
const char *ptr = getauxptr (AT_EXECFN);
|
||||
if (ptr == NULL)
|
||||
{
|
||||
printf ("warning: AT_EXECFN not support, cannot run test\n");
|
||||
exit (EXIT_UNSUPPORTED);
|
||||
}
|
||||
char *test_program_directory = dirname (xstrdup ((const char *) ptr));
|
||||
char *test_program_directory = dirname (xstrdup (ptr));
|
||||
TEST_VERIFY (setenv ("GCONV_PATH", test_program_directory, 1) == 0);
|
||||
free (test_program_directory);
|
||||
}
|
||||
|
||||
@@ -58,11 +58,11 @@ worker (void * arg)
|
||||
|
||||
char ascii[] = CONV_INPUT;
|
||||
char *inbufpos = ascii;
|
||||
size_t inbytesleft = sizeof (CONV_INPUT);
|
||||
size_t inbytesleft = sizeof (CONV_INPUT) - 1;
|
||||
|
||||
char *utf8 = xcalloc (sizeof (CONV_INPUT), 1);
|
||||
char *outbufpos = utf8;
|
||||
size_t outbytesleft = sizeof (CONV_INPUT);
|
||||
size_t outbytesleft = sizeof (CONV_INPUT) - 1;
|
||||
|
||||
if (tidx < TCOUNT/2)
|
||||
/* The first half of the worker thread pool synchronize together here,
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/param.h>
|
||||
#include <libc-pointer-arith.h>
|
||||
|
||||
/* struct alloc_buffer objects refer to a region of bytes in memory of a
|
||||
fixed size. The functions below can be used to allocate single
|
||||
@@ -248,9 +249,9 @@ __alloc_buffer_alloc (struct alloc_buffer *buf, size_t size, size_t align)
|
||||
if (size == 1 && align == 1)
|
||||
return alloc_buffer_alloc_bytes (buf, size);
|
||||
|
||||
size_t current = buf->__alloc_buffer_current;
|
||||
size_t aligned = roundup (current, align);
|
||||
size_t new_current = aligned + size;
|
||||
uintptr_t current = buf->__alloc_buffer_current;
|
||||
uintptr_t aligned = roundup (current, align);
|
||||
uintptr_t new_current = aligned + size;
|
||||
if (aligned >= current /* No overflow in align step. */
|
||||
&& new_current >= size /* No overflow in size computation. */
|
||||
&& new_current <= buf->__alloc_buffer_end) /* Room in buffer. */
|
||||
@@ -282,8 +283,8 @@ __alloc_buffer_next (struct alloc_buffer *buf, size_t align)
|
||||
if (align == 1)
|
||||
return (const void *) buf->__alloc_buffer_current;
|
||||
|
||||
size_t current = buf->__alloc_buffer_current;
|
||||
size_t aligned = roundup (current, align);
|
||||
uintptr_t current = buf->__alloc_buffer_current;
|
||||
uintptr_t aligned = roundup (current, align);
|
||||
if (aligned >= current /* No overflow in align step. */
|
||||
&& aligned <= buf->__alloc_buffer_end) /* Room in buffer. */
|
||||
{
|
||||
|
||||
+15
-2
@@ -62,6 +62,8 @@
|
||||
__atg1_result = pre##_32_##post (mem, __VA_ARGS__); \
|
||||
else if (sizeof (*mem) == 8) \
|
||||
__atg1_result = pre##_64_##post (mem, __VA_ARGS__); \
|
||||
else if (sizeof (*mem) == 16) \
|
||||
__atg1_result = pre##_128_##post (mem, __VA_ARGS__); \
|
||||
else \
|
||||
abort (); \
|
||||
__atg1_result; \
|
||||
@@ -77,6 +79,8 @@
|
||||
__atg2_result = pre##_32_##post (mem, __VA_ARGS__); \
|
||||
else if (sizeof (*mem) == 8) \
|
||||
__atg2_result = pre##_64_##post (mem, __VA_ARGS__); \
|
||||
else if (sizeof (*mem) == 16) \
|
||||
__atg2_result = pre##_128_##post (mem, __VA_ARGS__); \
|
||||
else \
|
||||
abort (); \
|
||||
__atg2_result; \
|
||||
@@ -540,7 +544,11 @@
|
||||
/* We require 32b atomic operations; some archs also support 64b atomic
|
||||
operations. */
|
||||
void __atomic_link_error (void);
|
||||
# if __HAVE_64B_ATOMICS == 1
|
||||
# if defined __CHERI_PURE_CAPABILITY__
|
||||
# define __atomic_check_size(mem) \
|
||||
if ((sizeof (*mem) != 4) && (sizeof (*mem) != 8) && (sizeof (*mem) != 16)) \
|
||||
__atomic_link_error ();
|
||||
# elif __HAVE_64B_ATOMICS == 1
|
||||
# define __atomic_check_size(mem) \
|
||||
if ((sizeof (*mem) != 4) && (sizeof (*mem) != 8)) \
|
||||
__atomic_link_error ();
|
||||
@@ -553,7 +561,12 @@ void __atomic_link_error (void);
|
||||
need other atomic operations of such sizes, and restricting the support to
|
||||
loads and stores makes this easier for archs that do not have native
|
||||
support for atomic operations to less-than-word-sized data. */
|
||||
# if __HAVE_64B_ATOMICS == 1
|
||||
# if defined __CHERI_PURE_CAPABILITY__
|
||||
# define __atomic_check_size_ls(mem) \
|
||||
if ((sizeof (*mem) != 1) && (sizeof (*mem) != 2) && (sizeof (*mem) != 4) \
|
||||
&& (sizeof (*mem) != 8) && (sizeof (*mem) != 16)) \
|
||||
__atomic_link_error ();
|
||||
# elif __HAVE_64B_ATOMICS == 1
|
||||
# define __atomic_check_size_ls(mem) \
|
||||
if ((sizeof (*mem) != 1) && (sizeof (*mem) != 2) && (sizeof (*mem) != 4) \
|
||||
&& (sizeof (*mem) != 8)) \
|
||||
|
||||
+17
-3
@@ -83,6 +83,7 @@ struct r_search_path_struct
|
||||
extern struct r_search_path_struct __rtld_search_dirs attribute_hidden;
|
||||
extern struct r_search_path_struct __rtld_env_path_list attribute_hidden;
|
||||
|
||||
|
||||
/* Structure describing a loaded shared object. The `l_next' and `l_prev'
|
||||
members form a chain of all the shared objects loaded at startup.
|
||||
|
||||
@@ -96,9 +97,9 @@ struct link_map
|
||||
{
|
||||
/* These first few members are part of the protocol with the debugger.
|
||||
This is the same format used in SVR4. */
|
||||
|
||||
ElfW(Addr) l_addr; /* Difference between the address in the ELF
|
||||
file and the addresses in memory. */
|
||||
|
||||
char *l_name; /* Absolute file name object was found in. */
|
||||
ElfW(Dyn) *l_ld; /* Dynamic section of the shared object. */
|
||||
struct link_map *l_next, *l_prev; /* Chain of loaded objects. */
|
||||
@@ -133,7 +134,7 @@ struct link_map
|
||||
ElfW(Dyn) *l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM
|
||||
+ DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM];
|
||||
const ElfW(Phdr) *l_phdr; /* Pointer to program header table in core. */
|
||||
ElfW(Addr) l_entry; /* Entry point location. */
|
||||
elfptr_t l_entry; /* Entry point location. */
|
||||
ElfW(Half) l_phnum; /* Number of program header entries. */
|
||||
ElfW(Half) l_ldnum; /* Number of dynamic segment entries. */
|
||||
|
||||
@@ -252,9 +253,22 @@ struct link_map
|
||||
|
||||
/* Start and finish of memory map for this object. l_map_start
|
||||
need not be the same as l_addr. */
|
||||
ElfW(Addr) l_map_start, l_map_end;
|
||||
elfptr_t l_map_start;
|
||||
ElfW(Addr) l_map_end;
|
||||
/* End of the executable part of the mapping. */
|
||||
ElfW(Addr) l_text_end;
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
/* Writable part of the mapping (may have non-writable holes). */
|
||||
elfptr_t l_rw_start;
|
||||
# define DL_MAX_RW_COUNT 4
|
||||
/* Writable ranges: objects are writable in these ranges. */
|
||||
int l_rw_count;
|
||||
struct rw_range
|
||||
{
|
||||
ElfW(Addr) start;
|
||||
ElfW(Addr) end;
|
||||
} l_rw_range[DL_MAX_RW_COUNT];
|
||||
#endif
|
||||
|
||||
/* Default array for 'l_scope'. */
|
||||
struct r_scope_elem *l_scope_mem[4];
|
||||
|
||||
@@ -10,4 +10,8 @@ libc_hidden_proto (__getauxval)
|
||||
_Bool __getauxval2 (unsigned long int type, unsigned long int *result);
|
||||
libc_hidden_proto (__getauxval2)
|
||||
|
||||
/* Like getauxval, but for Arm Morello capabilities. */
|
||||
extern __typeof (getauxptr) __getauxptr;
|
||||
libc_hidden_proto (__getauxptr)
|
||||
|
||||
#endif /* !_ISOMAC */
|
||||
|
||||
+4
-2
@@ -340,8 +340,10 @@ read_alias_file (const char *fname, int fname_len)
|
||||
|
||||
for (i = 0; i < nmap; i++)
|
||||
{
|
||||
map[i].alias += new_pool - string_space;
|
||||
map[i].value += new_pool - string_space;
|
||||
map[i].alias = new_pool
|
||||
+ (map[i].alias - string_space);
|
||||
map[i].value = new_pool
|
||||
+ (map[i].value - string_space);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94";
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fts.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
@@ -67,7 +68,7 @@ static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94";
|
||||
#endif
|
||||
/* Align P to that size. */
|
||||
#ifndef ALIGN
|
||||
#define ALIGN(p) (((unsigned long int) (p) + ALIGNBYTES) & ~ALIGNBYTES)
|
||||
#define ALIGN(p) (((uintptr_t) (p) + ALIGNBYTES) & ~ALIGNBYTES)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -95,7 +95,9 @@ struct _IO_FILE_complete
|
||||
size_t __pad5;
|
||||
int _mode;
|
||||
/* Make sure we don't get into trouble again. */
|
||||
char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
|
||||
char _unused2[sizeof (void *) == 4 * sizeof (int)
|
||||
? 9 * sizeof (int)
|
||||
: 15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
|
||||
};
|
||||
|
||||
/* These macros are used by bits/stdio.h and internal headers. */
|
||||
|
||||
+2
-2
@@ -247,8 +247,8 @@ __libc_tsd_define (extern, locale_t, LOCALE)
|
||||
But with thread-local locale settings, it becomes quite ungainly unless
|
||||
we can use __thread variables. So only in that case do we attempt this. */
|
||||
#ifndef SHARED
|
||||
# include <tls.h>
|
||||
# define NL_CURRENT_INDIRECT 1
|
||||
//# include <tls.h>
|
||||
//# define NL_CURRENT_INDIRECT 1
|
||||
#endif
|
||||
|
||||
#ifdef NL_CURRENT_INDIRECT
|
||||
|
||||
@@ -84,6 +84,13 @@ static const char *locnames[] =
|
||||
/* Size of the reserved address space area. */
|
||||
#define RESERVE_MMAP_SIZE 512 * 1024 * 1024
|
||||
|
||||
/* On CHERI targets ensure the mmap returned capability has RW permissions. */
|
||||
#ifdef PROT_MAX
|
||||
# define PROT_MAX_RW PROT_MAX (PROT_READ | PROT_WRITE)
|
||||
#else
|
||||
# define PROT_MAX_RW 0
|
||||
#endif
|
||||
|
||||
/* To prepare for enlargements of the mmaped area reserve some address
|
||||
space. On some machines, being a file mapping rather than an anonymous
|
||||
mapping affects the address selection. So do this mapping from the
|
||||
@@ -94,7 +101,8 @@ prepare_address_space (int fd, size_t total, size_t *reserved, int *xflags,
|
||||
{
|
||||
if (total < RESERVE_MMAP_SIZE)
|
||||
{
|
||||
void *p = mmap64 (NULL, RESERVE_MMAP_SIZE, PROT_NONE, MAP_SHARED, fd, 0);
|
||||
void *p = mmap64 (NULL, RESERVE_MMAP_SIZE,
|
||||
PROT_NONE | PROT_MAX_RW, MAP_SHARED, fd, 0);
|
||||
if (p != MAP_FAILED)
|
||||
{
|
||||
void *aligned_p = PTR_ALIGN_UP (p, MAP_FIXED_ALIGNMENT);
|
||||
|
||||
@@ -88,6 +88,7 @@ tests-exclude-hugetlb1 = \
|
||||
tst-interpose-thread \
|
||||
tst-interpose-static-nothread \
|
||||
tst-interpose-static-thread \
|
||||
tst-malloc-backtrace \
|
||||
tst-malloc-usable \
|
||||
tst-malloc-usable-tunables \
|
||||
tst-mallocstate
|
||||
@@ -159,6 +160,8 @@ libmemusage-inhibit-o = $(filter-out .os,$(object-suffixes))
|
||||
libc_malloc_debug-routines = malloc-debug $(sysdep_malloc_debug_routines)
|
||||
libc_malloc_debug-inhibit-o = $(filter-out .os,$(object-suffixes))
|
||||
|
||||
tst-malloc-backtrace-ENV = GLIBC_TUNABLES=glibc.mem.cap_narrowing=0
|
||||
|
||||
$(objpfx)tst-malloc-backtrace: $(shared-thread-library)
|
||||
$(objpfx)tst-malloc-thread-exit: $(shared-thread-library)
|
||||
$(objpfx)tst-malloc-thread-fail: $(shared-thread-library)
|
||||
@@ -331,12 +334,14 @@ $(objpfx)tst-interpose-static-thread: \
|
||||
$(objpfx)tst-interpose-aux-thread.o $(static-thread-library)
|
||||
|
||||
tst-dynarray-ENV = MALLOC_TRACE=$(objpfx)tst-dynarray.mtrace \
|
||||
GLIBC_TUNABLES=glibc.mem.cap_narrowing=0 \
|
||||
LD_PRELOAD=$(objpfx)libc_malloc_debug.so
|
||||
$(objpfx)tst-dynarray-mem.out: $(objpfx)tst-dynarray.out
|
||||
$(common-objpfx)malloc/mtrace $(objpfx)tst-dynarray.mtrace > $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
tst-dynarray-fail-ENV = MALLOC_TRACE=$(objpfx)tst-dynarray-fail.mtrace \
|
||||
GLIBC_TUNABLES=glibc.mem.cap_narrowing=0 \
|
||||
LD_PRELOAD=$(objpfx)libc_malloc_debug.so
|
||||
$(objpfx)tst-dynarray-fail-mem.out: $(objpfx)tst-dynarray-fail.out
|
||||
$(common-objpfx)malloc/mtrace $(objpfx)tst-dynarray-fail.mtrace > $@; \
|
||||
|
||||
@@ -23,12 +23,12 @@ void *
|
||||
__libc_alloc_buffer_alloc_array (struct alloc_buffer *buf, size_t element_size,
|
||||
size_t align, size_t count)
|
||||
{
|
||||
size_t current = buf->__alloc_buffer_current;
|
||||
uintptr_t current = buf->__alloc_buffer_current;
|
||||
/* The caller asserts that align is a power of two. */
|
||||
size_t aligned = ALIGN_UP (current, align);
|
||||
uintptr_t aligned = ALIGN_UP (current, align);
|
||||
size_t size;
|
||||
bool overflow = __builtin_mul_overflow (element_size, count, &size);
|
||||
size_t new_current = aligned + size;
|
||||
uintptr_t new_current = aligned + size;
|
||||
if (!overflow /* Multiplication did not overflow. */
|
||||
&& aligned >= current /* No overflow in align step. */
|
||||
&& new_current >= size /* No overflow in size computation. */
|
||||
|
||||
+26
-3
@@ -191,6 +191,7 @@ __malloc_fork_lock_parent (void)
|
||||
if (ar_ptr == &main_arena)
|
||||
break;
|
||||
}
|
||||
cap_fork_lock ();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -199,6 +200,8 @@ __malloc_fork_unlock_parent (void)
|
||||
if (!__malloc_initialized)
|
||||
return;
|
||||
|
||||
cap_fork_unlock_parent ();
|
||||
|
||||
for (mstate ar_ptr = &main_arena;; )
|
||||
{
|
||||
__libc_lock_unlock (ar_ptr->mutex);
|
||||
@@ -215,6 +218,8 @@ __malloc_fork_unlock_child (void)
|
||||
if (!__malloc_initialized)
|
||||
return;
|
||||
|
||||
cap_fork_unlock_child ();
|
||||
|
||||
/* Push all arenas to the free list, except thread_arena, which is
|
||||
attached to the current thread. */
|
||||
__libc_lock_init (free_list_lock);
|
||||
@@ -321,6 +326,14 @@ ptmalloc_init (void)
|
||||
tcache_key_initialize ();
|
||||
#endif
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
if (TUNABLE_GET_FULL (glibc, mem, cap_narrowing, int32_t, NULL) == 0)
|
||||
cap_narrowing_enabled = false;
|
||||
else
|
||||
cap_narrowing_enabled = true;
|
||||
#endif
|
||||
cap_init ();
|
||||
|
||||
#ifdef USE_MTAG
|
||||
if ((TUNABLE_GET_FULL (glibc, mem, tagging, int32_t, NULL) & 1) != 0)
|
||||
{
|
||||
@@ -444,7 +457,7 @@ dump_heap (heap_info *heap)
|
||||
fprintf (stderr, "Heap %p, size %10lx:\n", heap, (long) heap->size);
|
||||
ptr = (heap->ar_ptr != (mstate) (heap + 1)) ?
|
||||
(char *) (heap + 1) : (char *) (heap + 1) + sizeof (struct malloc_state);
|
||||
p = (mchunkptr) (((unsigned long) ptr + MALLOC_ALIGN_MASK) &
|
||||
p = (mchunkptr) (((uintptr_t) ptr + MALLOC_ALIGN_MASK) &
|
||||
~MALLOC_ALIGN_MASK);
|
||||
for (;; )
|
||||
{
|
||||
@@ -518,7 +531,7 @@ alloc_new_heap (size_t size, size_t top_pad, size_t pagesize,
|
||||
p1 = (char *) MMAP (0, max_size << 1, PROT_NONE, mmap_flags);
|
||||
if (p1 != MAP_FAILED)
|
||||
{
|
||||
p2 = (char *) (((unsigned long) p1 + (max_size - 1))
|
||||
p2 = (char *) (((uintptr_t) p1 + (max_size - 1))
|
||||
& ~(max_size - 1));
|
||||
ul = p2 - p1;
|
||||
if (ul)
|
||||
@@ -526,6 +539,9 @@ alloc_new_heap (size_t size, size_t top_pad, size_t pagesize,
|
||||
else
|
||||
aligned_heap_area = p2 + max_size;
|
||||
__munmap (p2 + max_size, max_size - ul);
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
p2 = __builtin_cheri_bounds_set_exact (p2, max_size);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -548,6 +564,12 @@ alloc_new_heap (size_t size, size_t top_pad, size_t pagesize,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!cap_map_add (p2))
|
||||
{
|
||||
__munmap (p2, max_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
madvise_thp (p2, size);
|
||||
|
||||
h = (heap_info *) p2;
|
||||
@@ -670,6 +692,7 @@ heap_trim (heap_info *heap, size_t pad)
|
||||
LIBC_PROBE (memory_heap_free, 2, heap, heap->size);
|
||||
if ((char *) heap + max_size == aligned_heap_area)
|
||||
aligned_heap_area = NULL;
|
||||
cap_map_del (heap);
|
||||
__munmap (heap, max_size);
|
||||
heap = prev_heap;
|
||||
if (!prev_inuse (p)) /* consolidate backward */
|
||||
@@ -760,7 +783,7 @@ _int_new_arena (size_t size)
|
||||
|
||||
/* Set up the top chunk, with proper alignment. */
|
||||
ptr = (char *) (a + 1);
|
||||
misalign = (unsigned long) chunk2mem (ptr) & MALLOC_ALIGN_MASK;
|
||||
misalign = (uintptr_t) chunk2mem (ptr) & MALLOC_ALIGN_MASK;
|
||||
if (misalign > 0)
|
||||
ptr += MALLOC_ALIGNMENT - misalign;
|
||||
top (a) = (mchunkptr) ptr;
|
||||
|
||||
+363
-22
@@ -244,6 +244,9 @@
|
||||
/* For memory tagging. */
|
||||
#include <libc-mtag.h>
|
||||
|
||||
/* For CHERI capability narrowing. */
|
||||
#include <libc-cap.h>
|
||||
|
||||
#include <malloc/malloc-internal.h>
|
||||
|
||||
/* For SINGLE_THREAD_P. */
|
||||
@@ -341,8 +344,12 @@ Fatal glibc error: malloc assertion failure in %s: %s\n",
|
||||
It assumes a minimum page size of 4096 bytes (12 bits). Systems with
|
||||
larger pages provide less entropy, although the pointer mangling
|
||||
still works. */
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
#define PROTECT_PTR(pos, ptr) (ptr)
|
||||
#else
|
||||
#define PROTECT_PTR(pos, ptr) \
|
||||
((__typeof (ptr)) ((((size_t) pos) >> 12) ^ ((size_t) ptr)))
|
||||
#endif
|
||||
#define REVEAL_PTR(ptr) PROTECT_PTR (&ptr, ptr)
|
||||
|
||||
/*
|
||||
@@ -478,6 +485,153 @@ tag_at (void *ptr)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* CHERI capability narrowing support. */
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
static bool cap_narrowing_enabled = true;
|
||||
#else
|
||||
# define cap_narrowing_enabled 0
|
||||
#endif
|
||||
|
||||
static __always_inline void
|
||||
cap_init (void)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
assert (__libc_cap_init ());
|
||||
}
|
||||
|
||||
static __always_inline void
|
||||
cap_fork_lock (void)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
__libc_cap_fork_lock ();
|
||||
}
|
||||
|
||||
static __always_inline void
|
||||
cap_fork_unlock_parent (void)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
__libc_cap_fork_unlock_parent ();
|
||||
}
|
||||
|
||||
static __always_inline void
|
||||
cap_fork_unlock_child (void)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
__libc_cap_fork_unlock_child ();
|
||||
}
|
||||
|
||||
static __always_inline bool
|
||||
cap_map_add (void *p)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
return __libc_cap_map_add (p);
|
||||
return true;
|
||||
}
|
||||
|
||||
static __always_inline void
|
||||
cap_map_del (void *p)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
__libc_cap_map_del (p);
|
||||
}
|
||||
|
||||
/* Round up size so capability bounds can be represented. */
|
||||
static __always_inline size_t
|
||||
cap_roundup (size_t n)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
return __libc_cap_roundup (n);
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Alignment such that capability bounds can be represented. */
|
||||
static __always_inline size_t
|
||||
cap_align (size_t n)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
return __libc_cap_align (n);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Narrow the bounds of p to [p, p+n) exactly unless p is NULL.
|
||||
Must match a previous cap_reserve call. */
|
||||
static __always_inline void *
|
||||
cap_narrow (void *p, size_t n)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
{
|
||||
if (p == NULL)
|
||||
__libc_cap_unreserve ();
|
||||
else
|
||||
p = __libc_cap_narrow (p, n);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Used in realloc if p is already narrowed or NULL.
|
||||
Must match a previous cap_reserve call. */
|
||||
static __always_inline bool
|
||||
cap_narrow_check (void *p, void *oldp)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
{
|
||||
if (p == NULL)
|
||||
(void) __libc_cap_narrow (oldp, 0);
|
||||
else
|
||||
__libc_cap_unreserve ();
|
||||
}
|
||||
return p != NULL;
|
||||
}
|
||||
|
||||
/* Used in realloc if p is new allocation or NULL but not yet narrowed.
|
||||
Must match a previous cap_reserve call. */
|
||||
static __always_inline void *
|
||||
cap_narrow_try (void *p, size_t n, void *oldp)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
{
|
||||
if (p == NULL)
|
||||
(void) __libc_cap_narrow (oldp, 0);
|
||||
else
|
||||
p = __libc_cap_narrow (p, n);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Widen back the bounds of a non-NULL p that was returned by cap_narrow. */
|
||||
static __always_inline void *
|
||||
cap_widen (void *p)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
return __libc_cap_widen (p);
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Reserve memory for the following cap_narrow, this may fail with ENOMEM. */
|
||||
static __always_inline bool
|
||||
cap_reserve (void)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
return __libc_cap_reserve ();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Release the reserved memory by cap_reserve. */
|
||||
static __always_inline void
|
||||
cap_unreserve (void)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
__libc_cap_unreserve ();
|
||||
}
|
||||
|
||||
/* Remove p so cap_widen no longer works on it. */
|
||||
static __always_inline void
|
||||
cap_drop (void *p)
|
||||
{
|
||||
if (cap_narrowing_enabled)
|
||||
__libc_cap_drop (p);
|
||||
}
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
@@ -1130,8 +1284,16 @@ static mchunkptr mremap_chunk(mchunkptr p, size_t new_size);
|
||||
# define MAP_NORESERVE 0
|
||||
#endif
|
||||
|
||||
/* Allow RW mprotect later, on CHERI this means RW capability permission. */
|
||||
#ifdef PROT_MAX
|
||||
# define PROT_MAX_RW PROT_MAX (PROT_READ | PROT_WRITE)
|
||||
#else
|
||||
# define PROT_MAX_RW 0
|
||||
#endif
|
||||
|
||||
#define MMAP(addr, size, prot, flags) \
|
||||
__mmap((addr), (size), (prot), (flags)|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)
|
||||
__mmap((addr), (size), (prot)|PROT_MAX_RW, \
|
||||
(flags)|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)
|
||||
|
||||
|
||||
/*
|
||||
@@ -1288,6 +1450,18 @@ nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
_int_memalign: Returns untagged memory.
|
||||
_mid_memalign: Returns tagged memory.
|
||||
_int_realloc: Takes and returns tagged memory.
|
||||
|
||||
With CHERI capability narrowing enabled, public interfaces take and
|
||||
return pointers with bounds that cannot access malloc internal chunk
|
||||
headers. Narrowing CHERI capabilities in internal interfaces:
|
||||
|
||||
sysmalloc: Returns wide capability.
|
||||
_int_malloc: Returns wide capability.
|
||||
_int_free: Takes wide capability.
|
||||
_int_memalign: Returns wide capability.
|
||||
_int_memalign: Returns wide capability.
|
||||
_mid_memalign: Returns narrow capability.
|
||||
_int_realloc: Takes and returns wide capability.
|
||||
*/
|
||||
|
||||
/* The chunk header is two SIZE_SZ elements, but this is used widely, so
|
||||
@@ -2438,6 +2612,12 @@ sysmalloc_mmap (INTERNAL_SIZE_T nb, size_t pagesize, int extra_flags, mstate av)
|
||||
if (mm == MAP_FAILED)
|
||||
return mm;
|
||||
|
||||
if (!cap_map_add (mm))
|
||||
{
|
||||
__munmap (mm, size);
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
#ifdef MAP_HUGETLB
|
||||
if (!(extra_flags & MAP_HUGETLB))
|
||||
madvise_thp (mm, size);
|
||||
@@ -2523,6 +2703,12 @@ sysmalloc_mmap_fallback (long int *s, INTERNAL_SIZE_T nb,
|
||||
if (mbrk == MAP_FAILED)
|
||||
return MAP_FAILED;
|
||||
|
||||
if (!cap_map_add (mbrk))
|
||||
{
|
||||
__munmap (mbrk, size);
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
#ifdef MAP_HUGETLB
|
||||
if (!(extra_flags & MAP_HUGETLB))
|
||||
madvise_thp (mbrk, size);
|
||||
@@ -3056,6 +3242,8 @@ munmap_chunk (mchunkptr p)
|
||||
atomic_decrement (&mp_.n_mmaps);
|
||||
atomic_add (&mp_.mmapped_mem, -total_size);
|
||||
|
||||
cap_map_del ((void *) block);
|
||||
|
||||
/* If munmap failed the process virtual memory address space is in a
|
||||
bad shape. Just leave the block hanging around, the process will
|
||||
terminate shortly anyway since not much can be done. */
|
||||
@@ -3094,6 +3282,9 @@ mremap_chunk (mchunkptr p, size_t new_size)
|
||||
if (cp == MAP_FAILED)
|
||||
return 0;
|
||||
|
||||
cap_map_del ((void *) block);
|
||||
cap_map_add (cp);
|
||||
|
||||
madvise_thp (cp, new_size);
|
||||
|
||||
p = (mchunkptr) (cp + offset);
|
||||
@@ -3193,6 +3384,35 @@ tcache_get (size_t tc_idx)
|
||||
return (void *) e;
|
||||
}
|
||||
|
||||
/* Cut down __libc_free for cleaning up tcache entries. */
|
||||
static void
|
||||
tcache_libc_free (void *mem)
|
||||
{
|
||||
int err = errno;
|
||||
mchunkptr p = mem2chunk(mem);
|
||||
if (chunk_is_mmapped (p))
|
||||
{
|
||||
/* See if the dynamic brk/mmap threshold needs adjusting.
|
||||
Dumped fake mmapped chunks do not affect the threshold. */
|
||||
if (!mp_.no_dyn_threshold
|
||||
&& chunksize_nomask (p) > mp_.mmap_threshold
|
||||
&& chunksize_nomask (p) <= DEFAULT_MMAP_THRESHOLD_MAX)
|
||||
{
|
||||
mp_.mmap_threshold = chunksize (p);
|
||||
mp_.trim_threshold = 2 * mp_.mmap_threshold;
|
||||
LIBC_PROBE (memory_mallopt_free_dyn_thresholds, 2,
|
||||
mp_.mmap_threshold, mp_.trim_threshold);
|
||||
}
|
||||
munmap_chunk (p);
|
||||
}
|
||||
else
|
||||
{
|
||||
mstate ar_ptr = arena_for_chunk (p);
|
||||
_int_free (ar_ptr, p, 0);
|
||||
}
|
||||
__set_errno (err);
|
||||
}
|
||||
|
||||
static void
|
||||
tcache_thread_shutdown (void)
|
||||
{
|
||||
@@ -3218,11 +3438,11 @@ tcache_thread_shutdown (void)
|
||||
malloc_printerr ("tcache_thread_shutdown(): "
|
||||
"unaligned tcache chunk detected");
|
||||
tcache_tmp->entries[i] = REVEAL_PTR (e->next);
|
||||
__libc_free (e);
|
||||
tcache_libc_free (e);
|
||||
}
|
||||
}
|
||||
|
||||
__libc_free (tcache_tmp);
|
||||
tcache_libc_free (tcache_tmp);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -3287,7 +3507,13 @@ __libc_malloc (size_t bytes)
|
||||
|
||||
if (!__malloc_initialized)
|
||||
ptmalloc_init ();
|
||||
|
||||
size_t align = cap_align (bytes);
|
||||
bytes = cap_roundup (bytes);
|
||||
#if USE_TCACHE
|
||||
_Static_assert (MAX_TCACHE_SIZE <= __CAP_ALIGN_THRESHOLD,
|
||||
"tcache entries are already aligned for capability narrowing");
|
||||
|
||||
/* int_free also calls request2size, be careful to not pad twice. */
|
||||
size_t tbytes = checked_request2size (bytes);
|
||||
if (tbytes == 0)
|
||||
@@ -3304,17 +3530,28 @@ __libc_malloc (size_t bytes)
|
||||
&& tcache
|
||||
&& tcache->counts[tc_idx] > 0)
|
||||
{
|
||||
if (!cap_reserve ())
|
||||
return NULL;
|
||||
victim = tcache_get (tc_idx);
|
||||
return tag_new_usable (victim);
|
||||
victim = tag_new_usable (victim);
|
||||
victim = cap_narrow (victim, bytes);
|
||||
return victim;
|
||||
}
|
||||
DIAG_POP_NEEDS_COMMENT;
|
||||
#endif
|
||||
|
||||
if (align > MALLOC_ALIGNMENT)
|
||||
return _mid_memalign (align, bytes, 0);
|
||||
|
||||
if (!cap_reserve ())
|
||||
return NULL;
|
||||
|
||||
if (SINGLE_THREAD_P)
|
||||
{
|
||||
victim = tag_new_usable (_int_malloc (&main_arena, bytes));
|
||||
assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
|
||||
&main_arena == arena_for_chunk (mem2chunk (victim)));
|
||||
victim = cap_narrow (victim, bytes);
|
||||
return victim;
|
||||
}
|
||||
|
||||
@@ -3337,6 +3574,7 @@ __libc_malloc (size_t bytes)
|
||||
|
||||
assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
|
||||
ar_ptr == arena_for_chunk (mem2chunk (victim)));
|
||||
victim = cap_narrow (victim, bytes);
|
||||
return victim;
|
||||
}
|
||||
libc_hidden_def (__libc_malloc)
|
||||
@@ -3350,6 +3588,9 @@ __libc_free (void *mem)
|
||||
if (mem == 0) /* free(0) has no effect */
|
||||
return;
|
||||
|
||||
mem = cap_widen (mem);
|
||||
cap_drop (mem);
|
||||
|
||||
/* Quickly check that the freed pointer matches the tag for the memory.
|
||||
This gives a useful double-free detection. */
|
||||
if (__glibc_unlikely (mtag_enabled))
|
||||
@@ -3411,6 +3652,8 @@ __libc_realloc (void *oldmem, size_t bytes)
|
||||
if (oldmem == 0)
|
||||
return __libc_malloc (bytes);
|
||||
|
||||
oldmem = cap_widen (oldmem);
|
||||
|
||||
/* Perform a quick check to ensure that the pointer's tag matches the
|
||||
memory's tag. */
|
||||
if (__glibc_unlikely (mtag_enabled))
|
||||
@@ -3437,6 +3680,8 @@ __libc_realloc (void *oldmem, size_t bytes)
|
||||
|| __builtin_expect (misaligned_chunk (oldp), 0)))
|
||||
malloc_printerr ("realloc(): invalid pointer");
|
||||
|
||||
size_t align = cap_align (bytes);
|
||||
bytes = cap_roundup (bytes);
|
||||
nb = checked_request2size (bytes);
|
||||
if (nb == 0)
|
||||
{
|
||||
@@ -3444,10 +3689,23 @@ __libc_realloc (void *oldmem, size_t bytes)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Every return path below should unreserve using the cap_narrow* apis. */
|
||||
if (!cap_reserve ())
|
||||
return NULL;
|
||||
cap_drop (oldmem);
|
||||
|
||||
if (chunk_is_mmapped (oldp))
|
||||
{
|
||||
void *newmem;
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
size_t pagesize = GLRO (dl_pagesize);
|
||||
|
||||
// TODO: with pcuabi kernel more cases can be handled by mremap
|
||||
/* Don't try in-place realloc if oldmem is unaligned. */
|
||||
if (align <= pagesize && ((size_t) oldmem & (align - 1)) == 0)
|
||||
{
|
||||
#endif
|
||||
#if HAVE_MREMAP
|
||||
newp = mremap_chunk (oldp, nb);
|
||||
if (newp)
|
||||
@@ -3458,30 +3716,65 @@ __libc_realloc (void *oldmem, size_t bytes)
|
||||
reused. There's a performance hit for both us and the
|
||||
caller for doing this, so we might want to
|
||||
reconsider. */
|
||||
return tag_new_usable (newmem);
|
||||
newmem = tag_new_usable (newmem);
|
||||
newmem = cap_narrow_try (newmem, bytes, oldmem);
|
||||
return newmem;
|
||||
}
|
||||
#endif
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
}
|
||||
size_t sz = oldsize - CHUNK_HDR_SZ;
|
||||
/* In-place realloc if the size shrinks, but if it shrinks a lot
|
||||
then don't waste the rest of the mapping. */
|
||||
if (sz >= bytes && sz / 4 < bytes
|
||||
&& ((size_t) oldmem & (align - 1)) == 0)
|
||||
return cap_narrow (oldmem, bytes);
|
||||
#else
|
||||
/* Note the extra SIZE_SZ overhead. */
|
||||
if (oldsize - SIZE_SZ >= nb)
|
||||
return oldmem; /* do nothing */
|
||||
#endif
|
||||
|
||||
/* Must alloc, copy, free. */
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
if (align > MALLOC_ALIGNMENT)
|
||||
newmem = _mid_memalign (align, bytes, 0);
|
||||
else
|
||||
#endif
|
||||
newmem = __libc_malloc (bytes);
|
||||
if (newmem == 0)
|
||||
if (!cap_narrow_check (newmem, oldmem))
|
||||
return 0; /* propagate failure */
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
memcpy (newmem, oldmem, sz < bytes ? sz : bytes);
|
||||
#else
|
||||
memcpy (newmem, oldmem, oldsize - CHUNK_HDR_SZ);
|
||||
#endif
|
||||
munmap_chunk (oldp);
|
||||
return newmem;
|
||||
}
|
||||
|
||||
/* Large alignment is required and it's not possible to realloc in place. */
|
||||
if (align > MALLOC_ALIGNMENT
|
||||
&& (oldsize < nb || ((size_t) oldmem & (align - 1)) != 0))
|
||||
{
|
||||
/* Use memalign, copy, free. */
|
||||
void *newmem = _mid_memalign (align, bytes, 0);
|
||||
if (!cap_narrow_check (newmem, oldmem))
|
||||
return newmem;
|
||||
size_t sz = oldsize - CHUNK_HDR_SZ;
|
||||
memcpy (newmem, oldmem, sz < bytes ? sz : bytes);
|
||||
(void) tag_region (oldmem, sz);
|
||||
_int_free (ar_ptr, oldp, 0);
|
||||
return newmem;
|
||||
}
|
||||
|
||||
if (SINGLE_THREAD_P)
|
||||
{
|
||||
newp = _int_realloc (ar_ptr, oldp, oldsize, nb);
|
||||
assert (!newp || chunk_is_mmapped (mem2chunk (newp)) ||
|
||||
ar_ptr == arena_for_chunk (mem2chunk (newp)));
|
||||
|
||||
return newp;
|
||||
return cap_narrow_try (newp, bytes, oldmem);
|
||||
}
|
||||
|
||||
__libc_lock_lock (ar_ptr->mutex);
|
||||
@@ -3497,14 +3790,15 @@ __libc_realloc (void *oldmem, size_t bytes)
|
||||
/* Try harder to allocate memory in other arenas. */
|
||||
LIBC_PROBE (memory_realloc_retry, 2, bytes, oldmem);
|
||||
newp = __libc_malloc (bytes);
|
||||
if (newp != NULL)
|
||||
{
|
||||
size_t sz = memsize (oldp);
|
||||
memcpy (newp, oldmem, sz);
|
||||
(void) tag_region (chunk2mem (oldp), sz);
|
||||
_int_free (ar_ptr, oldp, 0);
|
||||
}
|
||||
if (!cap_narrow_check (newp, oldmem))
|
||||
return NULL;
|
||||
size_t sz = memsize (oldp);
|
||||
memcpy (newp, oldmem, sz);
|
||||
(void) tag_region (chunk2mem (oldp), sz);
|
||||
_int_free (ar_ptr, oldp, 0);
|
||||
}
|
||||
else
|
||||
newp = cap_narrow (newp, bytes);
|
||||
|
||||
return newp;
|
||||
}
|
||||
@@ -3517,6 +3811,11 @@ __libc_memalign (size_t alignment, size_t bytes)
|
||||
ptmalloc_init ();
|
||||
|
||||
void *address = RETURN_ADDRESS (0);
|
||||
|
||||
size_t align = cap_align (bytes);
|
||||
bytes = cap_roundup (bytes);
|
||||
if (align > alignment)
|
||||
alignment = align;
|
||||
return _mid_memalign (alignment, bytes, address);
|
||||
}
|
||||
|
||||
@@ -3542,6 +3841,8 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!cap_reserve ())
|
||||
return NULL;
|
||||
|
||||
/* Make sure alignment is power of 2. */
|
||||
if (!powerof2 (alignment))
|
||||
@@ -3557,7 +3858,9 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
|
||||
p = _int_memalign (&main_arena, alignment, bytes);
|
||||
assert (!p || chunk_is_mmapped (mem2chunk (p)) ||
|
||||
&main_arena == arena_for_chunk (mem2chunk (p)));
|
||||
return tag_new_usable (p);
|
||||
p = tag_new_usable (p);
|
||||
p = cap_narrow (p, bytes);
|
||||
return p;
|
||||
}
|
||||
|
||||
arena_get (ar_ptr, bytes + alignment + MINSIZE);
|
||||
@@ -3575,7 +3878,9 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
|
||||
|
||||
assert (!p || chunk_is_mmapped (mem2chunk (p)) ||
|
||||
ar_ptr == arena_for_chunk (mem2chunk (p)));
|
||||
return tag_new_usable (p);
|
||||
p = tag_new_usable (p);
|
||||
p = cap_narrow (p, bytes);
|
||||
return p;
|
||||
}
|
||||
/* For ISO C11. */
|
||||
weak_alias (__libc_memalign, aligned_alloc)
|
||||
@@ -3589,6 +3894,10 @@ __libc_valloc (size_t bytes)
|
||||
|
||||
void *address = RETURN_ADDRESS (0);
|
||||
size_t pagesize = GLRO (dl_pagesize);
|
||||
size_t align = cap_align (bytes);
|
||||
bytes = cap_roundup (bytes);
|
||||
if (align > pagesize)
|
||||
pagesize = align;
|
||||
return _mid_memalign (pagesize, bytes, address);
|
||||
}
|
||||
|
||||
@@ -3611,6 +3920,10 @@ __libc_pvalloc (size_t bytes)
|
||||
}
|
||||
rounded_bytes = rounded_bytes & -(pagesize - 1);
|
||||
|
||||
size_t align = cap_align (rounded_bytes);
|
||||
rounded_bytes = cap_roundup (rounded_bytes);
|
||||
if (align > pagesize)
|
||||
pagesize = align;
|
||||
return _mid_memalign (pagesize, rounded_bytes, address);
|
||||
}
|
||||
|
||||
@@ -3633,12 +3946,28 @@ __libc_calloc (size_t n, size_t elem_size)
|
||||
}
|
||||
|
||||
sz = bytes;
|
||||
sz = cap_roundup (sz);
|
||||
|
||||
if (!__malloc_initialized)
|
||||
ptmalloc_init ();
|
||||
|
||||
size_t align = cap_align (bytes);
|
||||
if (align > MALLOC_ALIGNMENT)
|
||||
{
|
||||
mem = _mid_memalign (align, sz, 0);
|
||||
if (mem == NULL)
|
||||
return mem;
|
||||
mchunkptr p = mem2chunk (cap_widen (mem));
|
||||
if (chunk_is_mmapped (p) && __glibc_likely (perturb_byte == 0))
|
||||
return mem;
|
||||
return memset (mem, 0, sz);
|
||||
}
|
||||
|
||||
MAYBE_INIT_TCACHE ();
|
||||
|
||||
if (!cap_reserve ())
|
||||
return NULL;
|
||||
|
||||
if (SINGLE_THREAD_P)
|
||||
av = &main_arena;
|
||||
else
|
||||
@@ -3690,6 +4019,8 @@ __libc_calloc (size_t n, size_t elem_size)
|
||||
}
|
||||
|
||||
/* Allocation failed even after a retry. */
|
||||
if (mem == 0)
|
||||
cap_unreserve ();
|
||||
if (mem == 0)
|
||||
return 0;
|
||||
|
||||
@@ -3699,13 +4030,19 @@ __libc_calloc (size_t n, size_t elem_size)
|
||||
regardless of MORECORE_CLEARS, so we zero the whole block while
|
||||
doing so. */
|
||||
if (__glibc_unlikely (mtag_enabled))
|
||||
return tag_new_zero_region (mem, memsize (p));
|
||||
{
|
||||
mem = tag_new_zero_region (mem, memsize (p));
|
||||
mem = cap_narrow (mem, sz);
|
||||
return mem;
|
||||
}
|
||||
|
||||
INTERNAL_SIZE_T csz = chunksize (p);
|
||||
|
||||
/* Two optional cases in which clearing not necessary */
|
||||
if (chunk_is_mmapped (p))
|
||||
{
|
||||
mem = cap_narrow (mem, sz);
|
||||
|
||||
if (__builtin_expect (perturb_byte, 0))
|
||||
return memset (mem, 0, sz);
|
||||
|
||||
@@ -3729,8 +4066,7 @@ __libc_calloc (size_t n, size_t elem_size)
|
||||
assert (nclears >= 3);
|
||||
|
||||
if (nclears > 9)
|
||||
return memset (d, 0, clearsize);
|
||||
|
||||
mem = memset (mem, 0, clearsize);
|
||||
else
|
||||
{
|
||||
*(d + 0) = 0;
|
||||
@@ -3753,6 +4089,7 @@ __libc_calloc (size_t n, size_t elem_size)
|
||||
}
|
||||
}
|
||||
|
||||
mem = cap_narrow (mem, sz);
|
||||
return mem;
|
||||
}
|
||||
#endif /* IS_IN (libc) */
|
||||
@@ -4978,8 +5315,7 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
|
||||
we can move to the next aligned spot -- we've allocated enough
|
||||
total room so that this is always possible.
|
||||
*/
|
||||
brk = (char *) mem2chunk (((unsigned long) (m + alignment - 1)) &
|
||||
- ((signed long) alignment));
|
||||
brk = (char *) mem2chunk (m + alignment - ((unsigned long) (m) % alignment));
|
||||
if ((unsigned long) (brk - (char *) (p)) < MINSIZE)
|
||||
brk += alignment;
|
||||
|
||||
@@ -5135,6 +5471,7 @@ __malloc_usable_size (void *m)
|
||||
{
|
||||
if (m == NULL)
|
||||
return 0;
|
||||
m = cap_widen (m);
|
||||
return musable (m);
|
||||
}
|
||||
#endif
|
||||
@@ -5681,6 +6018,10 @@ __posix_memalign (void **memptr, size_t alignment, size_t size)
|
||||
|| alignment == 0)
|
||||
return EINVAL;
|
||||
|
||||
size_t align = cap_align (size);
|
||||
size = cap_roundup (size);
|
||||
if (align > alignment)
|
||||
alignment = align;
|
||||
|
||||
void *address = RETURN_ADDRESS (0);
|
||||
mem = _mid_memalign (alignment, size, address);
|
||||
|
||||
@@ -74,7 +74,7 @@ checkhdr (const struct hdr *hdr)
|
||||
an error and report it. */
|
||||
return MCHECK_OK;
|
||||
|
||||
switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next))
|
||||
switch (hdr->magic ^ ((unsigned long) hdr->prev + (unsigned long) hdr->next))
|
||||
{
|
||||
default:
|
||||
status = MCHECK_HEAD;
|
||||
|
||||
+3
-16
@@ -116,22 +116,9 @@
|
||||
# define PTR_INT_TYPE ptrdiff_t
|
||||
#endif
|
||||
|
||||
/* If B is the base of an object addressed by P, return the result of
|
||||
aligning P to the next multiple of A + 1. B and P must be of type
|
||||
char *. A + 1 must be a power of 2. */
|
||||
|
||||
#define __BPTR_ALIGN(B, P, A) ((B) + (((P) - (B) + (A)) & ~(A)))
|
||||
|
||||
/* Similar to _BPTR_ALIGN (B, P, A), except optimize the common case
|
||||
where pointers can be converted to integers, aligned as integers,
|
||||
and converted back again. If PTR_INT_TYPE is narrower than a
|
||||
pointer (e.g., the AS/400), play it safe and compute the alignment
|
||||
relative to B. Otherwise, use the faster strategy of computing the
|
||||
alignment relative to 0. */
|
||||
|
||||
#define __PTR_ALIGN(B, P, A) \
|
||||
__BPTR_ALIGN (sizeof (PTR_INT_TYPE) < sizeof (void *) ? (B) : (char *) 0, \
|
||||
P, A)
|
||||
/* Align P to the next multiple of A + 1, where A + 1 is a power of 2,
|
||||
A fits into unsigned long and P has type char *. */
|
||||
#define __PTR_ALIGN(B, P, A) ((P) + (-(unsigned long)(P) & (A)))
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
@@ -155,21 +155,13 @@ do_test (void)
|
||||
struct scratch_buffer buf;
|
||||
scratch_buffer_init (&buf);
|
||||
memset (buf.data, '@', buf.length);
|
||||
|
||||
size_t sizes[] = { 16, buf.length, buf.length + 16 };
|
||||
for (int i = 0; i < array_length (sizes); i++)
|
||||
{
|
||||
/* The extra size is unitialized through realloc. */
|
||||
size_t l = sizes[i] > buf.length ? sizes[i] : buf.length;
|
||||
void *r = scratch_buffer_dupfree (&buf, l);
|
||||
void *c = xmalloc (l);
|
||||
memset (c, '@', l);
|
||||
TEST_COMPARE_BLOB (r, l, buf.data, l);
|
||||
free (r);
|
||||
free (c);
|
||||
}
|
||||
|
||||
scratch_buffer_free (&buf);
|
||||
size_t l = 16 <= buf.length ? 16 : buf.length;
|
||||
void *r = scratch_buffer_dupfree (&buf, l);
|
||||
void *c = xmalloc (l);
|
||||
memset (c, '@', l);
|
||||
TEST_COMPARE_BLOB (r, l, c, l);
|
||||
free (r);
|
||||
free (c);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -612,3 +612,9 @@ support in the kernel if this tunable has any non-zero value.
|
||||
|
||||
The default value is @samp{0}, which disables all memory tagging.
|
||||
@end deftp
|
||||
|
||||
@deftp Tunable glibc.mem.cap_narrowing
|
||||
On CHERI architecture use capability bounds narrowing in the malloc
|
||||
implementation. By default it is set to 1, to disable bounds narrowing
|
||||
set it to 0.
|
||||
@end deftp
|
||||
|
||||
@@ -164,6 +164,9 @@ libc {
|
||||
GLIBC_2.32 {
|
||||
__libc_single_threaded;
|
||||
}
|
||||
GLIBC_2.37 {
|
||||
__getauxptr; getauxptr;
|
||||
}
|
||||
GLIBC_PRIVATE {
|
||||
__madvise;
|
||||
__mktemp;
|
||||
|
||||
@@ -20,6 +20,39 @@
|
||||
#include <ldsodefs.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void *
|
||||
__getauxptr (unsigned long int type)
|
||||
{
|
||||
/* error if asking for a non-pointer from getauxptr(). This list is not a
|
||||
perfect enforcement as it currently supports both transitional and draft
|
||||
ABIs, which have different capability entries. */
|
||||
switch (type) {
|
||||
case AT_ENTRY:
|
||||
case AT_PHDR:
|
||||
case AT_BASE:
|
||||
case AT_SYSINFO_EHDR:
|
||||
case AT_EXECFN:
|
||||
case AT_RANDOM:
|
||||
case AT_PLATFORM:
|
||||
case AT_CHERI_EXEC_RW_CAP:
|
||||
case AT_CHERI_EXEC_RX_CAP:
|
||||
case AT_CHERI_INTERP_RW_CAP:
|
||||
case AT_CHERI_INTERP_RX_CAP:
|
||||
case AT_CHERI_SEAL_CAP:
|
||||
{
|
||||
ElfW(auxv_t) *p;
|
||||
for (p = GLRO(dl_auxv); p->a_type != AT_NULL; p++)
|
||||
if (p->a_type == type)
|
||||
return (void *) p->a_un.a_val;
|
||||
}
|
||||
}
|
||||
|
||||
__set_errno (ENOENT);
|
||||
return 0;
|
||||
}
|
||||
weak_alias (__getauxptr, getauxptr)
|
||||
libc_hidden_def (__getauxptr)
|
||||
|
||||
bool
|
||||
__getauxval2 (unsigned long int type, unsigned long int *result)
|
||||
{
|
||||
|
||||
@@ -31,6 +31,10 @@ __BEGIN_DECLS
|
||||
extern unsigned long int getauxval (unsigned long int __type)
|
||||
__THROW;
|
||||
|
||||
/* Same as getauxval, but for Arm Morello capabilities. */
|
||||
extern void * getauxptr (unsigned long int __type)
|
||||
__THROW;
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* sys/auxv.h */
|
||||
|
||||
+4
-4
@@ -131,15 +131,15 @@ typedef struct node_t
|
||||
uintptr_t right_node;
|
||||
} *node;
|
||||
|
||||
#define RED(N) (node)((N)->left_node & ((uintptr_t) 0x1))
|
||||
#define RED(N) (unsigned int)((N)->left_node & ((uintptr_t) 0x1))
|
||||
#define SETRED(N) (N)->left_node |= ((uintptr_t) 0x1)
|
||||
#define SETBLACK(N) (N)->left_node &= ~((uintptr_t) 0x1)
|
||||
#define SETNODEPTR(NP,P) (*NP) = (node)((((uintptr_t)(*NP)) \
|
||||
#define SETNODEPTR(NP,P) (*NP) = (node)((unsigned int)(((uintptr_t)(*NP)) \
|
||||
& (uintptr_t) 0x1) | (uintptr_t)(P))
|
||||
#define LEFT(N) (node)((N)->left_node & ~((uintptr_t) 0x1))
|
||||
#define LEFTPTR(N) (node *)(&(N)->left_node)
|
||||
#define SETLEFT(N,L) (N)->left_node = (((N)->left_node & (uintptr_t) 0x1) \
|
||||
| (uintptr_t)(L))
|
||||
#define SETLEFT(N,L) (N)->left_node = ((unsigned int)((N)->left_node \
|
||||
& (uintptr_t) 0x1) | (uintptr_t)(L))
|
||||
#define RIGHT(N) (node)((N)->right_node)
|
||||
#define RIGHTPTR(N) (node *)(&(N)->right_node)
|
||||
#define SETRIGHT(N,R) (N)->right_node = (uintptr_t)(R)
|
||||
|
||||
@@ -52,6 +52,13 @@
|
||||
# define MAP_STACK 0
|
||||
#endif
|
||||
|
||||
/* On CHERI targets ensure the mmap returned capability has RW permissions. */
|
||||
#ifdef PROT_MAX
|
||||
# define PROT_MAX_RW PROT_MAX (PROT_READ | PROT_WRITE)
|
||||
#else
|
||||
# define PROT_MAX_RW 0
|
||||
#endif
|
||||
|
||||
/* Get a stack frame from the cache. We have to match by size since
|
||||
some blocks might be too small or far too large. */
|
||||
static struct pthread *
|
||||
@@ -363,7 +370,8 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
|
||||
/* If a guard page is required, avoid committing memory by first
|
||||
allocate with PROT_NONE and then reserve with required permission
|
||||
excluding the guard page. */
|
||||
mem = __mmap (NULL, size, (guardsize == 0) ? prot : PROT_NONE,
|
||||
mem = __mmap (NULL, size,
|
||||
(guardsize == 0) ? prot : PROT_NONE | PROT_MAX_RW,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
|
||||
|
||||
if (__glibc_unlikely (mem == MAP_FAILED))
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
#include <limits.h>
|
||||
#include "pthreadP.h"
|
||||
#include <shlib-compat.h>
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
# include <cheri_perms.h>
|
||||
#endif
|
||||
|
||||
#ifndef NEW_VERNUM
|
||||
# define NEW_VERNUM GLIBC_2_3_3
|
||||
@@ -43,6 +45,11 @@ __pthread_attr_setstack (pthread_attr_t *attr, void *stackaddr,
|
||||
EXTRA_PARAM_CHECKS;
|
||||
#endif
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
if (!STACK_CAP_CHECK (stackaddr, stacksize))
|
||||
return EINVAL;
|
||||
#endif
|
||||
|
||||
iattr->stacksize = stacksize;
|
||||
#if _STACK_GROWS_DOWN
|
||||
iattr->stackaddr = (char *) stackaddr + stacksize;
|
||||
|
||||
@@ -204,7 +204,11 @@ typedef __off64_t __loff_t; /* Type of file sizes and offsets (LFS). */
|
||||
typedef char *__caddr_t;
|
||||
|
||||
/* Duplicates info from stdint.h but this is used in unistd.h. */
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
__STD_TYPE __intcap_t __intptr_t;
|
||||
#else
|
||||
__STD_TYPE __SWORD_TYPE __intptr_t;
|
||||
#endif
|
||||
|
||||
/* Duplicate info from sys/socket.h. */
|
||||
__STD_TYPE __U32_TYPE __socklen_t;
|
||||
|
||||
@@ -7,7 +7,7 @@ main (void)
|
||||
int retval = 0;
|
||||
long int res;
|
||||
|
||||
res = ulimit (UL_SETFSIZE, 10000);
|
||||
res = ulimit (UL_SETFSIZE, 10000L);
|
||||
printf ("Result of ulimit (UL_SETFSIZE, 10000): %ld\n", res);
|
||||
if (res != 10000)
|
||||
retval = 1;
|
||||
|
||||
@@ -159,8 +159,24 @@ class Context(object):
|
||||
"""Add all known glibc build configurations."""
|
||||
self.add_config(arch='aarch64',
|
||||
os_name='linux-gnu',
|
||||
gcc_cfg=['--with-multilib-list=lp64,purecap',
|
||||
'--disable-libgomp', '--disable-libitm'],
|
||||
glibcs=[{},
|
||||
{'variant': 'purecap',
|
||||
'ccopts': '-mabi=purecap -march=morello+c64',
|
||||
'cfg': ['--disable-werror']}],
|
||||
extra_glibcs=[{'variant': 'disable-multi-arch',
|
||||
'cfg': ['--disable-multi-arch']}])
|
||||
'cfg': ['--disable-multi-arch']},
|
||||
{'variant': 'purecap-nopie',
|
||||
'ccopts': '-mabi=purecap -march=morello+c64',
|
||||
'cfg': ['--disable-werror', '--disable-default-pie']}])
|
||||
self.add_config(arch='aarch64',
|
||||
os_name='linux-gnu_purecap',
|
||||
gcc_cfg=['--with-abi=purecap', '--with-arch=morello+c64', '--disable-multilib',
|
||||
'--disable-libgomp', '--disable-libitm'],
|
||||
glibcs=[{'cfg': ['--disable-werror']}],
|
||||
extra_glibcs=[{'variant': 'nopie',
|
||||
'cfg': ['--disable-werror', '--disable-default-pie']}])
|
||||
self.add_config(arch='aarch64_be',
|
||||
os_name='linux-gnu')
|
||||
self.add_config(arch='arc',
|
||||
|
||||
@@ -177,7 +177,7 @@ END {
|
||||
n = indices[2];
|
||||
m = indices[3];
|
||||
printf (" {TUNABLE_NAME_S(%s, %s, %s)", t, n, m)
|
||||
printf (", {TUNABLE_TYPE_%s, %s, %s}, {%s}, NULL, TUNABLE_SECLEVEL_%s, %s},\n",
|
||||
printf (", {TUNABLE_TYPE_%s, %s, %s}, {%s}, false, TUNABLE_SECLEVEL_%s, %s},\n",
|
||||
types[t,n,m], minvals[t,n,m], maxvals[t,n,m],
|
||||
default_val[t,n,m], security_level[t,n,m], env_alias[t,n,m]);
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn,
|
||||
spec->info.pad = ' ';
|
||||
spec->info.wide = sizeof (UCHAR_T) > 1;
|
||||
spec->info.is_binary128 = 0;
|
||||
spec->info.is_cap = 0;
|
||||
|
||||
/* Test for positional argument. */
|
||||
if (ISDIGIT (*format))
|
||||
@@ -371,6 +372,10 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn,
|
||||
break;
|
||||
case L'p':
|
||||
spec->data_arg_type = PA_POINTER;
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
if (spec->info.alt)
|
||||
spec->info.is_cap = 1;
|
||||
#endif
|
||||
break;
|
||||
case L'n':
|
||||
spec->data_arg_type = PA_INT|PA_FLAG_PTR;
|
||||
|
||||
@@ -50,7 +50,8 @@ struct printf_info
|
||||
unsigned int i18n:1; /* I flag. */
|
||||
unsigned int is_binary128:1; /* Floating-point argument is ABI-compatible
|
||||
with IEC 60559 binary128. */
|
||||
unsigned int __pad:3; /* Unused so far. */
|
||||
unsigned int is_cap:1; /* CHERI capability. */
|
||||
unsigned int __pad:2; /* Unused so far. */
|
||||
unsigned short int user; /* Bits for user-installed modifiers. */
|
||||
wchar_t pad; /* Padding character. */
|
||||
};
|
||||
|
||||
@@ -67,6 +67,7 @@ main (void)
|
||||
buf[2049] = 0x84;
|
||||
buf[2058] = '\t';
|
||||
buf[2059] = 'a';
|
||||
buf[sizeof (buf) - 1] = '\0';
|
||||
if (sscanf (buf, "%ms%mc", &sp1, &sp2) != 2)
|
||||
FAIL ();
|
||||
else
|
||||
|
||||
@@ -116,6 +116,10 @@
|
||||
while (0)
|
||||
#endif
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
# include <cheri_perms.h>
|
||||
#endif
|
||||
|
||||
/* Add LENGTH to DONE. Return the new value of DONE, or -1 on
|
||||
overflow (and set errno accordingly). */
|
||||
static inline int
|
||||
@@ -792,6 +796,9 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
|
||||
int base;
|
||||
union printf_arg the_arg;
|
||||
CHAR_T *string; /* Pointer to argument string. */
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
const void *cap = 0;
|
||||
#endif
|
||||
int alt = 0; /* Alternate format. */
|
||||
int space = 0; /* Use space prefix if no sign is needed. */
|
||||
int left = 0; /* Left-justify output. */
|
||||
@@ -805,6 +812,9 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
|
||||
int is_char = 0; /* Argument is promoted (unsigned) char. */
|
||||
int width = 0; /* Width of output; 0 means none specified. */
|
||||
int prec = -1; /* Precision of output; -1 means none specified. */
|
||||
__attribute__((unused))
|
||||
int is_cap = 0; /* Argument is a capability. */
|
||||
|
||||
/* This flag is set by the 'I' modifier and selects the use of the
|
||||
`outdigits' as determined by the current locale. */
|
||||
int use_outdigits = 0;
|
||||
@@ -1324,6 +1334,9 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
|
||||
} number;
|
||||
int base;
|
||||
CHAR_T *string; /* Pointer to argument string. */
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
const void *cap = 0;
|
||||
#endif
|
||||
|
||||
/* Fill variables from values in struct. */
|
||||
int alt = specs[nspecs_done].info.alt;
|
||||
@@ -1338,6 +1351,8 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
|
||||
int is_long = specs[nspecs_done].info.is_long;
|
||||
int width = specs[nspecs_done].info.width;
|
||||
int prec = specs[nspecs_done].info.prec;
|
||||
__attribute__((unused))
|
||||
int is_cap = specs[nspecs_done].info.is_cap;
|
||||
int use_outdigits = specs[nspecs_done].info.i18n;
|
||||
char pad = specs[nspecs_done].info.pad;
|
||||
CHAR_T spec = specs[nspecs_done].info.spec;
|
||||
|
||||
@@ -25,6 +25,115 @@
|
||||
{
|
||||
/* Start real work. We know about all flags and modifiers and
|
||||
now process the wanted format specifier. */
|
||||
|
||||
/* Process capability information according to the CHERI C Programming guide:
|
||||
https://github.com/CTSRD-CHERI/cheri-c-programming/wiki/Displaying-Capabilities */
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
LABEL (capability):
|
||||
/* CHERI capability. */
|
||||
{
|
||||
uint64_t cap_perm = 0;
|
||||
uint64_t cap_base = 0;
|
||||
uint64_t cap_limit = 0;
|
||||
uint64_t cap_tag = 0;
|
||||
uint64_t cap_type = 0;
|
||||
outchar (L_(' '));
|
||||
outchar (L_('['));
|
||||
cap_perm = __builtin_cheri_perms_get (cap);
|
||||
if (cap_perm & CAP_PERM_LOAD)
|
||||
outchar (L_('r'));
|
||||
if (cap_perm & CAP_PERM_STORE)
|
||||
outchar (L_('w'));
|
||||
if (cap_perm & CAP_PERM_EXECUTE)
|
||||
outchar (L_('x'));
|
||||
if (cap_perm & CAP_PERM_LOAD_CAP)
|
||||
outchar (L_('R'));
|
||||
if (cap_perm & CAP_PERM_STORE_CAP)
|
||||
outchar (L_('W'));
|
||||
if (cap_perm & CAP_PERM_EXECUTIVE)
|
||||
outchar (L_('E'));
|
||||
outchar (L_(','));
|
||||
cap_base = __builtin_cheri_base_get (cap);
|
||||
number.word = (unsigned long int) cap_base;
|
||||
if (prec < 0)
|
||||
prec = 1;
|
||||
else
|
||||
pad = L_(' ');
|
||||
string = _itoa_word (number.word, workend, base, spec == L_('X'));
|
||||
prec = MAX (0, prec - (workend - string));
|
||||
width -= workend - string + prec;
|
||||
if (number.word != 0)
|
||||
width -= 2;
|
||||
if (pad == L_(' '))
|
||||
{
|
||||
PAD (L_(' '));
|
||||
width = 0;
|
||||
}
|
||||
if (number.word != 0)
|
||||
{
|
||||
outchar (L_('0'));
|
||||
outchar (spec);
|
||||
}
|
||||
width += prec;
|
||||
PAD (L_('0'));
|
||||
outstring (string, workend - string);
|
||||
outchar (L_('-'));
|
||||
cap_limit = __builtin_cheri_length_get (cap) + cap_base;
|
||||
number.word = (unsigned long int) cap_limit;
|
||||
if (prec < 0)
|
||||
prec = 1;
|
||||
else
|
||||
pad = L_(' ');
|
||||
string = _itoa_word (number.word, workend, base, spec == L_('X'));
|
||||
prec = MAX (0, prec - (workend - string));
|
||||
width -= workend - string + prec;
|
||||
if (number.word != 0)
|
||||
width -= 2;
|
||||
if (pad == L_(' '))
|
||||
{
|
||||
PAD (L_(' '));
|
||||
width = 0;
|
||||
}
|
||||
if (number.word != 0)
|
||||
{
|
||||
outchar (L_('0'));
|
||||
outchar (spec);
|
||||
}
|
||||
width += prec;
|
||||
PAD (L_('0'));
|
||||
outstring (string, workend - string);
|
||||
outchar (L_(']'));
|
||||
cap_tag = __builtin_cheri_tag_get (cap);
|
||||
if (!cap_tag)
|
||||
{
|
||||
outchar (L_(' '));
|
||||
outchar (L_('('));
|
||||
outstring ("invalid", 8);
|
||||
outchar (L_(')'));
|
||||
break;
|
||||
}
|
||||
cap_type = __builtin_cheri_type_get (cap);
|
||||
if (cap_type != 0)
|
||||
{
|
||||
if (cap_type == 1)
|
||||
{
|
||||
outchar (L_(' '));
|
||||
outchar (L_('('));
|
||||
outstring ("sentry", 7);
|
||||
outchar (L_(')'));
|
||||
}
|
||||
else
|
||||
{
|
||||
outchar (L_(' '));
|
||||
outchar (L_('('));
|
||||
outstring ("sealed", 7);
|
||||
outchar (L_(')'));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
LABEL (form_percent):
|
||||
/* Write a literal "%". */
|
||||
outchar (L_('%'));
|
||||
@@ -212,6 +321,11 @@ LABEL (unsigned_number): /* Unsigned number of base BASE. */
|
||||
|
||||
outstring (string, workend - string);
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
if (is_cap == 1)
|
||||
goto LABEL(capability);
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
@@ -265,6 +379,13 @@ LABEL (form_pointer):
|
||||
base = 16;
|
||||
number.word = (unsigned long int) ptr;
|
||||
is_negative = 0;
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
if (alt == 1)
|
||||
{
|
||||
cap = ptr;
|
||||
is_cap = 1;
|
||||
}
|
||||
#endif
|
||||
alt = 1;
|
||||
group = 0;
|
||||
spec = L_('x');
|
||||
|
||||
@@ -64,9 +64,17 @@ __correctly_grouped_prefixmb (const STRING_TYPE *begin, const STRING_TYPE *end,
|
||||
thousands_len = strlen (thousands);
|
||||
#endif
|
||||
|
||||
#ifdef USE_WIDE_CHAR
|
||||
while (end > begin)
|
||||
#else
|
||||
while (end - begin >= thousands_len)
|
||||
#endif
|
||||
{
|
||||
#ifdef USE_WIDE_CHAR
|
||||
const STRING_TYPE *cp = end - 1;
|
||||
#else
|
||||
const STRING_TYPE *cp = end - thousands_len;
|
||||
#endif
|
||||
const char *gp = grouping;
|
||||
|
||||
/* Check first group. */
|
||||
|
||||
@@ -289,6 +289,10 @@ __qsort_r (void *b, size_t n, size_t s, __compar_d_fn_t cmp, void *arg)
|
||||
&& ((char *) b - (char *) 0) % __alignof__ (uint64_t) == 0)
|
||||
p.var = 1;
|
||||
else if ((s & (sizeof (unsigned long) - 1)) == 0
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
&& ((char *) b - (char *) 0)
|
||||
% __alignof__ (void *) != 0
|
||||
#endif
|
||||
&& ((char *) b - (char *) 0)
|
||||
% __alignof__ (unsigned long) == 0)
|
||||
p.var = 2;
|
||||
|
||||
@@ -84,10 +84,22 @@ typedef unsigned long long int uint_fast64_t;
|
||||
/* Types for `void *' pointers. */
|
||||
#if __WORDSIZE == 64
|
||||
# ifndef __intptr_t_defined
|
||||
# ifdef __CHERI_PURE_CAPABILITY__
|
||||
typedef __intcap_t intptr_t;
|
||||
# else
|
||||
typedef long int intptr_t;
|
||||
# endif
|
||||
# define __intptr_t_defined
|
||||
# endif
|
||||
# ifdef __CHERI_PURE_CAPABILITY__
|
||||
typedef __uintcap_t uintptr_t;
|
||||
# else
|
||||
typedef unsigned long int uintptr_t;
|
||||
# endif
|
||||
# if defined __CHERI__ && !defined __CHERI_PURE_CAPABILITY__
|
||||
typedef __uintcap_t uintcap_t;
|
||||
typedef __intcap_t intcap_t;
|
||||
# endif
|
||||
#else
|
||||
# ifndef __intptr_t_defined
|
||||
typedef int intptr_t;
|
||||
|
||||
@@ -63,7 +63,7 @@ last (void)
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
do_test (void)
|
||||
{
|
||||
int value;
|
||||
void *dso;
|
||||
@@ -90,3 +90,5 @@ main (void)
|
||||
|
||||
FAIL_EXIT1 ("Did not terminate via exit(0) in exit_thread() as expected.");
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
||||
|
||||
+7
-6
@@ -27,6 +27,7 @@
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -529,7 +530,7 @@ test_strlen (void)
|
||||
char *p;
|
||||
for (i=0; i < 0x100; i++)
|
||||
{
|
||||
p = (char *) ((unsigned long int)(buf + 0xff) & ~0xff) + i;
|
||||
p = (char *) ((uintptr_t)(buf + 0xff) & ~0xff) + i;
|
||||
strcpy (p, "OK");
|
||||
strcpy (p+3, "BAD/WRONG");
|
||||
check (strlen (p) == 2, 4+i);
|
||||
@@ -554,7 +555,7 @@ test_strnlen (void)
|
||||
char buf[4096];
|
||||
for (int i = 0; i < 0x100; ++i)
|
||||
{
|
||||
char *p = (char *) ((unsigned long int)(buf + 0xff) & ~0xff) + i;
|
||||
char *p = (char *) ((uintptr_t)(buf + 0xff) & ~0xff) + i;
|
||||
strcpy (p, "OK");
|
||||
strcpy (p + 3, "BAD/WRONG");
|
||||
check (strnlen (p, 100) == 2, 10 + i);
|
||||
@@ -582,7 +583,7 @@ test_strchr (void)
|
||||
char *p;
|
||||
for (i=0; i < 0x100; i++)
|
||||
{
|
||||
p = (char *) ((unsigned long int) (buf + 0xff) & ~0xff) + i;
|
||||
p = (char *) ((uintptr_t) (buf + 0xff) & ~0xff) + i;
|
||||
strcpy (p, "OK");
|
||||
strcpy (p+3, "BAD/WRONG");
|
||||
check (strchr (p, '/') == NULL, 9+i);
|
||||
@@ -614,7 +615,7 @@ test_strchrnul (void)
|
||||
char *p;
|
||||
for (i=0; i < 0x100; i++)
|
||||
{
|
||||
p = (char *) ((unsigned long int) (buf + 0xff) & ~0xff) + i;
|
||||
p = (char *) ((uintptr_t) (buf + 0xff) & ~0xff) + i;
|
||||
strcpy (p, "OK");
|
||||
strcpy (p+3, "BAD/WRONG");
|
||||
cp = strchrnul (p, '/');
|
||||
@@ -643,7 +644,7 @@ test_rawmemchr (void)
|
||||
char *p;
|
||||
for (i=0; i < 0x100; i++)
|
||||
{
|
||||
p = (char *) ((unsigned long int) (buf + 0xff) & ~0xff) + i;
|
||||
p = (char *) ((uintptr_t) (buf + 0xff) & ~0xff) + i;
|
||||
strcpy (p, "OK");
|
||||
strcpy (p+3, "BAD/WRONG");
|
||||
check (rawmemchr (p, 'R') == p+8, 6+i);
|
||||
@@ -689,7 +690,7 @@ test_strrchr (void)
|
||||
char *p;
|
||||
for (i=0; i < 0x100; i++)
|
||||
{
|
||||
p = (char *) ((unsigned long int) (buf + 0xff) & ~0xff) + i;
|
||||
p = (char *) ((uintptr_t) (buf + 0xff) & ~0xff) + i;
|
||||
strcpy (p, "OK");
|
||||
strcpy (p+3, "BAD/WRONG");
|
||||
check (strrchr (p, '/') == NULL, 9+i);
|
||||
|
||||
@@ -151,7 +151,7 @@ allocate_big (size_t total_size, const void *element, size_t element_size,
|
||||
|
||||
/* Reserve the memory region. If we cannot create the mapping,
|
||||
there is no reason to set up the backing file. */
|
||||
void *target = mmap (NULL, total_size, PROT_NONE,
|
||||
void *target = mmap (NULL, total_size, PROT_NONE | PROT_MAX_RW,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
if (target == MAP_FAILED)
|
||||
return (struct support_blob_repeat) { 0 };
|
||||
|
||||
+40
-2
@@ -98,7 +98,8 @@ void support_record_failure (void);
|
||||
|
||||
/* Compare the two integers LEFT and RIGHT and report failure if they
|
||||
are different. */
|
||||
#define TEST_COMPARE(left, right) \
|
||||
#ifndef __CHERI_PURE_CAPABILITY__
|
||||
# define TEST_COMPARE(left, right) \
|
||||
({ \
|
||||
/* + applies the integer promotions, for bitfield support. */ \
|
||||
typedef __typeof__ (+ (left)) __left_type; \
|
||||
@@ -126,6 +127,32 @@ void support_record_failure (void);
|
||||
#left, __left_value, __left_is_positive, sizeof (__left_type), \
|
||||
#right, __right_value, __right_is_positive, sizeof (__right_type)); \
|
||||
})
|
||||
#else
|
||||
# define TEST_COMPARE(left, right) \
|
||||
({ \
|
||||
/* + applies the integer promotions, for bitfield support. */ \
|
||||
typedef __typeof__ (+ (left)) __left_type; \
|
||||
typedef __typeof__ (+ (right)) __right_type; \
|
||||
__left_type __left_value = (left); \
|
||||
__right_type __right_value = (right); \
|
||||
int __left_is_positive = __left_value > 0; \
|
||||
int __right_is_positive = __right_value > 0; \
|
||||
/* Prevent use with floating-point types. */ \
|
||||
support_static_assert ((__left_type) 1.0 == (__left_type) 1.5, \
|
||||
"left value has floating-point type"); \
|
||||
support_static_assert ((__right_type) 1.0 == (__right_type) 1.5, \
|
||||
"right value has floating-point type"); \
|
||||
/* Compare the value. */ \
|
||||
if (__left_value != __right_value \
|
||||
|| __left_is_positive != __right_is_positive) \
|
||||
/* Pass the sign for printing the correct value. */ \
|
||||
support_test_compare_failure \
|
||||
(__FILE__, __LINE__, \
|
||||
#left, __left_value, __left_is_positive, sizeof (__left_type), \
|
||||
#right, __right_value, __right_is_positive, sizeof (__right_type)); \
|
||||
})
|
||||
#endif
|
||||
|
||||
|
||||
/* Internal implementation of TEST_COMPARE. LEFT_POSITIVE and
|
||||
RIGHT_POSITIVE are used to store the sign separately, so that both
|
||||
@@ -133,6 +160,7 @@ void support_record_failure (void);
|
||||
RIGHT_VALUE, and the function can still print the original value.
|
||||
LEFT_SIZE and RIGHT_SIZE specify the size of the argument in bytes,
|
||||
for hexadecimal formatting. */
|
||||
#ifndef __CHERI_PURE_CAPABILITY__
|
||||
void support_test_compare_failure (const char *file, int line,
|
||||
const char *left_expr,
|
||||
long long left_value,
|
||||
@@ -142,7 +170,17 @@ void support_test_compare_failure (const char *file, int line,
|
||||
long long right_value,
|
||||
int right_positive,
|
||||
int right_size);
|
||||
|
||||
#else
|
||||
void support_test_compare_failure (const char *file, int line,
|
||||
const char *left_expr,
|
||||
__uintcap_t left_value,
|
||||
int left_positive,
|
||||
int left_size,
|
||||
const char *right_expr,
|
||||
__uintcap_t right_value,
|
||||
int right_positive,
|
||||
int right_size);
|
||||
#endif
|
||||
|
||||
/* Compare [LEFT, LEFT + LEFT_LENGTH) with [RIGHT, RIGHT +
|
||||
RIGHT_LENGTH) and report a test failure if the arrays are
|
||||
|
||||
@@ -60,7 +60,7 @@ support_stack_alloc (size_t size)
|
||||
so we know they are allocated. */
|
||||
void *alloc_base = xmmap (0,
|
||||
alloc_size,
|
||||
PROT_NONE,
|
||||
PROT_NONE|PROT_MAX_RW,
|
||||
MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE|MAP_STACK,
|
||||
-1);
|
||||
/* Some architecture still requires executable stack for the signal return
|
||||
|
||||
@@ -34,6 +34,7 @@ report (const char *which, const char *expr, long long value, int positive,
|
||||
printf (" (0x%llx); from: %s\n", (unsigned long long) value & mask, expr);
|
||||
}
|
||||
|
||||
#ifndef __CHERI_PURE_CAPABILITY__
|
||||
void
|
||||
support_test_compare_failure (const char *file, int line,
|
||||
const char *left_expr,
|
||||
@@ -56,3 +57,27 @@ support_test_compare_failure (const char *file, int line,
|
||||
report ("right", right_expr, right_value, right_positive, right_size);
|
||||
errno = saved_errno;
|
||||
}
|
||||
#else
|
||||
void
|
||||
support_test_compare_failure (const char *file, int line,
|
||||
const char *left_expr,
|
||||
__uintcap_t left_value,
|
||||
int left_positive,
|
||||
int left_size,
|
||||
const char *right_expr,
|
||||
__uintcap_t right_value,
|
||||
int right_positive,
|
||||
int right_size)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
support_record_failure ();
|
||||
if (left_size != right_size)
|
||||
printf ("%s:%d: numeric comparison failure (widths %d and %d)\n",
|
||||
file, line, left_size * 8, right_size * 8);
|
||||
else
|
||||
printf ("%s:%d: numeric comparison failure\n", file, line);
|
||||
report (" left", left_expr, left_value, left_positive, left_size);
|
||||
report ("right", right_expr, right_value, right_positive, right_size);
|
||||
errno = saved_errno;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
@@ -77,6 +78,13 @@ void xclose (int);
|
||||
/* Write the buffer. Retry on short writes. */
|
||||
void xwrite (int, const void *, size_t);
|
||||
|
||||
/* On CHERI targets ensure the mmap returned capability has RW permissions. */
|
||||
#ifdef PROT_MAX
|
||||
# define PROT_MAX_RW PROT_MAX (PROT_READ | PROT_WRITE)
|
||||
#else
|
||||
# define PROT_MAX_RW 0
|
||||
#endif
|
||||
|
||||
/* Invoke mmap with a zero file offset. */
|
||||
void *xmmap (void *addr, size_t length, int prot, int flags, int fd);
|
||||
void xmprotect (void *addr, size_t length, int prot);
|
||||
|
||||
@@ -9,7 +9,7 @@ LDFLAGS-rtld += -Wl,-z,force-bti,--fatal-warnings
|
||||
endif
|
||||
|
||||
ifeq ($(subdir),elf)
|
||||
sysdep-dl-routines += dl-bti
|
||||
sysdep-dl-routines += dl-bti dl-symaddr
|
||||
|
||||
tests += tst-audit26 \
|
||||
tst-audit27
|
||||
@@ -39,7 +39,7 @@ gen-as-const-headers += dl-link.sym
|
||||
|
||||
tests-internal += tst-ifunc-arg-1 tst-ifunc-arg-2
|
||||
|
||||
ifeq (yes,$(aarch64-variant-pcs))
|
||||
ifeq (yesyesno,$(aarch64-variant-pcs)$(build-shared)$(aarch64-purecap))
|
||||
tests += tst-vpcs
|
||||
modules-names += tst-vpcs-mod
|
||||
LDFLAGS-tst-vpcs-mod.so = -Wl,-z,lazy
|
||||
@@ -68,3 +68,9 @@ endif
|
||||
ifeq ($(subdir),malloc)
|
||||
sysdep_malloc_debug_routines = __mtag_tag_zero_region __mtag_tag_region
|
||||
endif
|
||||
|
||||
ifeq (yes,$(aarch64-purecap))
|
||||
ifeq ($(subdir),stdio-common)
|
||||
tests += tst-printf-cap
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -54,6 +54,13 @@
|
||||
model, __ATOMIC_RELAXED); \
|
||||
})
|
||||
|
||||
# define __arch_compare_and_exchange_bool_128_int(mem, newval, oldval, model) \
|
||||
({ \
|
||||
typeof (*mem) __oldval = (oldval); \
|
||||
!__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \
|
||||
model, __ATOMIC_RELAXED); \
|
||||
})
|
||||
|
||||
# define __arch_compare_and_exchange_val_8_int(mem, newval, oldval, model) \
|
||||
({ \
|
||||
typeof (*mem) __oldval = (oldval); \
|
||||
@@ -86,6 +93,14 @@
|
||||
__oldval; \
|
||||
})
|
||||
|
||||
# define __arch_compare_and_exchange_val_128_int(mem, newval, oldval, model) \
|
||||
({ \
|
||||
typeof (*mem) __oldval = (oldval); \
|
||||
__atomic_compare_exchange_n (mem, (void *) &__oldval, newval, 0, \
|
||||
model, __ATOMIC_RELAXED); \
|
||||
__oldval; \
|
||||
})
|
||||
|
||||
|
||||
/* Compare and exchange with "acquire" semantics, ie barrier after. */
|
||||
|
||||
@@ -118,6 +133,9 @@
|
||||
# define __arch_exchange_64_int(mem, newval, model) \
|
||||
__atomic_exchange_n (mem, newval, model)
|
||||
|
||||
# define __arch_exchange_128_int(mem, newval, model) \
|
||||
__atomic_exchange_n (mem, newval, model)
|
||||
|
||||
# define atomic_exchange_acq(mem, value) \
|
||||
__atomic_val_bysize (__arch_exchange, int, mem, value, __ATOMIC_ACQUIRE)
|
||||
|
||||
@@ -139,6 +157,9 @@
|
||||
# define __arch_exchange_and_add_64_int(mem, value, model) \
|
||||
__atomic_fetch_add (mem, value, model)
|
||||
|
||||
# define __arch_exchange_and_add_128_int(mem, value, model) \
|
||||
__atomic_fetch_add (mem, value, model)
|
||||
|
||||
# define atomic_exchange_and_add_acq(mem, value) \
|
||||
__atomic_val_bysize (__arch_exchange_and_add, int, mem, value, \
|
||||
__ATOMIC_ACQUIRE)
|
||||
|
||||
@@ -27,7 +27,10 @@
|
||||
/* Jump buffer contains:
|
||||
x19-x28, x29(fp), x30(lr), (x31)sp, d8-d15. Other registers are not
|
||||
saved. */
|
||||
# ifndef __CHERI_PURE_CAPABILITY__
|
||||
__extension__ typedef unsigned long long __jmp_buf [22];
|
||||
|
||||
# else
|
||||
__extension__ typedef __uintcap_t __jmp_buf [22];
|
||||
# endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifdef __LP64__
|
||||
#if defined __LP64__ || defined __CHERI_PURE_CAPABILITY__
|
||||
# define __WORDSIZE 64
|
||||
#else
|
||||
# define __WORDSIZE 32
|
||||
|
||||
+45
-9
@@ -1,10 +1,6 @@
|
||||
# This file is generated from configure.ac by Autoconf. DO NOT EDIT!
|
||||
# Local configure fragment for sysdeps/aarch64.
|
||||
|
||||
# Static PIE is supported.
|
||||
$as_echo "#define SUPPORT_STATIC_PIE 1" >>confdefs.h
|
||||
|
||||
|
||||
# We check to see if the compiler and flags are
|
||||
# selecting the big endian ABI and if they are then
|
||||
# we set libc_cv_aarch64_be to yes which causes
|
||||
@@ -167,16 +163,56 @@ rm -f conftest*
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_aarch64_be" >&5
|
||||
$as_echo "$libc_cv_aarch64_be" >&6; }
|
||||
# Check for purecap ABI too, an alternative name is l64pc128.
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for purecap ABI" >&5
|
||||
$as_echo_n "checking for purecap ABI... " >&6; }
|
||||
if ${libc_cv_aarch64_purecap+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
yes
|
||||
#endif
|
||||
|
||||
_ACEOF
|
||||
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
|
||||
$EGREP "yes" >/dev/null 2>&1; then :
|
||||
libc_cv_aarch64_purecap=yes
|
||||
else
|
||||
libc_cv_aarch64_purecap=no
|
||||
fi
|
||||
rm -f conftest*
|
||||
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_aarch64_purecap" >&5
|
||||
$as_echo "$libc_cv_aarch64_purecap" >&6; }
|
||||
config_vars="$config_vars
|
||||
aarch64-purecap = $libc_cv_aarch64_purecap"
|
||||
|
||||
libc_aarch64_be=""
|
||||
if test $libc_cv_aarch64_be = yes; then
|
||||
$as_echo "#define HAVE_AARCH64_BE 1" >>confdefs.h
|
||||
|
||||
config_vars="$config_vars
|
||||
default-abi = lp64_be"
|
||||
else
|
||||
config_vars="$config_vars
|
||||
default-abi = lp64"
|
||||
libc_aarch64_be="_be"
|
||||
fi
|
||||
|
||||
libc_aarch64_abi="lp64"
|
||||
if test $libc_cv_aarch64_purecap = yes; then
|
||||
libc_aarch64_abi="purecap"
|
||||
# The purecap abi requires relocations because objects may not be
|
||||
# within bounds for PCC. This means static-pie is not supported.
|
||||
$as_echo "#define HIDDEN_VAR_NEEDS_DYNAMIC_RELOC 1" >>confdefs.h
|
||||
|
||||
else
|
||||
# Static PIE is supported. Hidden variables only need relocations
|
||||
# in PIE with -mcmodel=large, but that's unsupported.
|
||||
$as_echo "#define SUPPORT_STATIC_PIE 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
config_vars="$config_vars
|
||||
default-abi = $libc_aarch64_abi$libc_aarch64_be"
|
||||
|
||||
# Only consider BTI supported if -mbranch-protection=bti is
|
||||
# on by default in the compiler and the linker produces
|
||||
# binaries with GNU property notes in PT_GNU_PROPERTY segment.
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
|
||||
# Local configure fragment for sysdeps/aarch64.
|
||||
|
||||
# Static PIE is supported.
|
||||
AC_DEFINE(SUPPORT_STATIC_PIE)
|
||||
|
||||
# We check to see if the compiler and flags are
|
||||
# selecting the big endian ABI and if they are then
|
||||
# we set libc_cv_aarch64_be to yes which causes
|
||||
@@ -17,13 +14,34 @@ AC_CACHE_CHECK([for big endian],
|
||||
yes
|
||||
#endif
|
||||
], libc_cv_aarch64_be=yes, libc_cv_aarch64_be=no)])
|
||||
# Check for purecap ABI too, an alternative name is l64pc128.
|
||||
AC_CACHE_CHECK([for purecap ABI],
|
||||
[libc_cv_aarch64_purecap],
|
||||
[AC_EGREP_CPP(yes,[#ifdef __CHERI_PURE_CAPABILITY__
|
||||
yes
|
||||
#endif
|
||||
], libc_cv_aarch64_purecap=yes, libc_cv_aarch64_purecap=no)])
|
||||
LIBC_CONFIG_VAR([aarch64-purecap], [$libc_cv_aarch64_purecap])
|
||||
|
||||
libc_aarch64_be=""
|
||||
if test $libc_cv_aarch64_be = yes; then
|
||||
AC_DEFINE(HAVE_AARCH64_BE)
|
||||
LIBC_CONFIG_VAR([default-abi], [lp64_be])
|
||||
else
|
||||
LIBC_CONFIG_VAR([default-abi], [lp64])
|
||||
libc_aarch64_be="_be"
|
||||
fi
|
||||
|
||||
libc_aarch64_abi="lp64"
|
||||
if test $libc_cv_aarch64_purecap = yes; then
|
||||
libc_aarch64_abi="purecap"
|
||||
# The purecap abi requires relocations because objects may not be
|
||||
# within bounds for PCC. This means static-pie is not supported.
|
||||
AC_DEFINE(HIDDEN_VAR_NEEDS_DYNAMIC_RELOC)
|
||||
else
|
||||
# Static PIE is supported. Hidden variables only need relocations
|
||||
# in PIE with -mcmodel=large, but that's unsupported.
|
||||
AC_DEFINE(SUPPORT_STATIC_PIE)
|
||||
fi
|
||||
LIBC_CONFIG_VAR([default-abi], [$libc_aarch64_abi$libc_aarch64_be])
|
||||
|
||||
# Only consider BTI supported if -mbranch-protection=bti is
|
||||
# on by default in the compiler and the linker produces
|
||||
# binaries with GNU property notes in PT_GNU_PROPERTY segment.
|
||||
|
||||
@@ -22,6 +22,14 @@
|
||||
|
||||
struct link_map;
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
/* Symbol pointer with correct capability permission and bounds. */
|
||||
void *_dl_symbol_address (struct link_map *map, const ElfW(Sym) *ref);
|
||||
rtld_hidden_proto (_dl_symbol_address)
|
||||
|
||||
# define DL_SYMBOL_ADDRESS(map, ref) _dl_symbol_address(map, ref)
|
||||
#endif
|
||||
|
||||
extern void _dl_unmap (struct link_map *map);
|
||||
|
||||
#define DL_UNMAP(map) _dl_unmap (map)
|
||||
|
||||
@@ -36,7 +36,8 @@
|
||||
static inline int __attribute__ ((unused))
|
||||
elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
|
||||
{
|
||||
return ehdr->e_machine == EM_AARCH64;
|
||||
return ehdr->e_machine == EM_AARCH64
|
||||
&& (ehdr->e_flags & EF_AARCH64_CHERI_PURECAP) == 0;
|
||||
}
|
||||
|
||||
/* Return the run-time load address of the shared object. */
|
||||
|
||||
@@ -22,6 +22,15 @@
|
||||
#include <elf.h>
|
||||
#include <cpu-features.h>
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
# define DO_ELF_MACHINE_REL_RELATIVE(map, l_addr, relative) \
|
||||
elf_machine_rela_relative (map, relative)
|
||||
|
||||
#define D_PTR_RW(map, i) \
|
||||
(dl_relocate_ld (map) ? (map)->i->d_un.d_ptr \
|
||||
: dl_rw_ptr ((map), (map)->i->d_un.d_ptr))
|
||||
#endif
|
||||
|
||||
struct La_aarch64_regs;
|
||||
struct La_aarch64_retval;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
struct link_map_machine
|
||||
{
|
||||
ElfW(Addr) plt; /* Address of .plt */
|
||||
elfptr_t plt; /* Address of .plt */
|
||||
void *tlsdesc_table; /* Address of TLS descriptor hash table. */
|
||||
bool bti_fail; /* Failed to enable Branch Target Identification. */
|
||||
};
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
ld {
|
||||
GLIBC_PRIVATE {
|
||||
# in ld.so, but used by libc.so too.
|
||||
_dl_symbol_address;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/* Copyright (C) 2022 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library. If not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <sysdep.h>
|
||||
#include <jmpbuf-offsets.h>
|
||||
#include <stap-probe.h>
|
||||
|
||||
/* __longjmp(jmpbuf, val) */
|
||||
|
||||
ENTRY (__longjmp)
|
||||
cfi_def_cfa(c0, 0)
|
||||
cfi_offset(c19, JB_X19<<4)
|
||||
cfi_offset(c20, JB_X20<<4)
|
||||
cfi_offset(c21, JB_X21<<4)
|
||||
cfi_offset(c22, JB_X22<<4)
|
||||
cfi_offset(c23, JB_X23<<4)
|
||||
cfi_offset(c24, JB_X24<<4)
|
||||
cfi_offset(c25, JB_X25<<4)
|
||||
cfi_offset(c26, JB_X26<<4)
|
||||
cfi_offset(c27, JB_X27<<4)
|
||||
cfi_offset(c28, JB_X28<<4)
|
||||
cfi_offset(c29, JB_X29<<4)
|
||||
cfi_offset(c30, JB_LR<<4)
|
||||
|
||||
cfi_offset(q8, JB_D8<<4)
|
||||
cfi_offset(q9, JB_D9<<4)
|
||||
cfi_offset(q10, JB_D10<<4)
|
||||
cfi_offset(q11, JB_D11<<4)
|
||||
cfi_offset(q12, JB_D12<<4)
|
||||
cfi_offset(q13, JB_D13<<4)
|
||||
cfi_offset(q14, JB_D14<<4)
|
||||
cfi_offset(q15, JB_D15<<4)
|
||||
|
||||
ldp c19, c20, [c0, #JB_X19<<4]
|
||||
ldp c21, c22, [c0, #JB_X21<<4]
|
||||
ldp c23, c24, [c0, #JB_X23<<4]
|
||||
ldp c25, c26, [c0, #JB_X25<<4]
|
||||
ldp c27, c28, [c0, #JB_X27<<4]
|
||||
ldp c29, c30, [c0, #JB_X29<<4]
|
||||
|
||||
/* longjmp probe takes 3 arguments, address of jump buffer as
|
||||
first argument (8@x0), return value as second argument (-4@x1),
|
||||
and target address (8@x30), respectively. */
|
||||
LIBC_PROBE (longjmp, 3, 8@c0, -4@c1, 8@c30)
|
||||
ldp q8, q9, [c0, #JB_D8<<4]
|
||||
ldp q10, q11, [c0, #JB_D10<<4]
|
||||
ldp q12, q13, [c0, #JB_D12<<4]
|
||||
ldp q14, q15, [c0, #JB_D14<<4]
|
||||
|
||||
/* Originally this was implemented with a series of
|
||||
.cfi_restore() directives.
|
||||
|
||||
The theory was that cfi_restore should revert to previous
|
||||
frame value is the same as the current value. In practice
|
||||
this doesn't work, even after cfi_restore() gdb continues
|
||||
to try to recover a previous frame value offset from x0,
|
||||
which gets stuffed after a few more instructions. The
|
||||
cfi_same_value() mechanism appears to work fine. */
|
||||
|
||||
cfi_same_value(c19)
|
||||
cfi_same_value(c20)
|
||||
cfi_same_value(c21)
|
||||
cfi_same_value(c22)
|
||||
cfi_same_value(c23)
|
||||
cfi_same_value(c24)
|
||||
cfi_same_value(c25)
|
||||
cfi_same_value(c26)
|
||||
cfi_same_value(c27)
|
||||
cfi_same_value(c28)
|
||||
cfi_same_value(c29)
|
||||
cfi_same_value(c30)
|
||||
cfi_same_value(q8)
|
||||
cfi_same_value(q9)
|
||||
cfi_same_value(q10)
|
||||
cfi_same_value(q11)
|
||||
cfi_same_value(q12)
|
||||
cfi_same_value(q13)
|
||||
cfi_same_value(q14)
|
||||
cfi_same_value(q15)
|
||||
|
||||
ldr c5, [c0, #JB_SP<<4]
|
||||
mov csp, c5
|
||||
|
||||
/* longjmp_target probe takes 3 arguments, address of jump buffer
|
||||
as first argument (8@x0), return value as second argument (-4@x1),
|
||||
and target address (8@x30), respectively. */
|
||||
LIBC_PROBE (longjmp_target, 3, 8@c0, -4@c1, 8@c30)
|
||||
cmp x1, #0
|
||||
mov x0, #1
|
||||
csel x0, x1, x0, ne
|
||||
/* Use br instead of ret because ret is guaranteed to mispredict */
|
||||
br c30
|
||||
END (__longjmp)
|
||||
@@ -0,0 +1,36 @@
|
||||
#include <stdint.h>
|
||||
#include <ldsodefs.h>
|
||||
#include <cheri_perms.h>
|
||||
|
||||
static inline uintptr_t
|
||||
morello_relative (uint64_t base, uintptr_t cap_rx, uintptr_t cap_rw,
|
||||
const ElfW(Rela) *reloc, void *reloc_addr)
|
||||
{
|
||||
uint64_t *__attribute__((may_alias)) u64_reloc_addr = reloc_addr;
|
||||
|
||||
/* Fragment identified by r_offset has the following information:
|
||||
| 64-bit: address | 56-bits: length | 8-bits: permissions | */
|
||||
unsigned long loc = u64_reloc_addr[0];
|
||||
unsigned long len = u64_reloc_addr[1] & ((1UL << 56) - 1);
|
||||
unsigned long perm = u64_reloc_addr[1] >> 56;
|
||||
uintptr_t value;
|
||||
|
||||
/* Permissions field is encoded as:
|
||||
4 = executable, 2 = read/write, 1 = read-only. */
|
||||
if (perm == 2)
|
||||
value = __builtin_cheri_address_set (cap_rw, base + loc);
|
||||
else
|
||||
value = __builtin_cheri_address_set (cap_rx, base + loc);
|
||||
|
||||
value = __builtin_cheri_bounds_set_exact (value, len);
|
||||
|
||||
value = value + reloc->r_addend;
|
||||
|
||||
if (perm == 1)
|
||||
value = __builtin_cheri_perms_and (value, CAP_PERM_MASK_R);
|
||||
|
||||
/* Seal executable capabilities with MORELLO_RB. */
|
||||
if (perm == 4)
|
||||
value = __builtin_cheri_seal_entry (value);
|
||||
return value;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/* Copyright (C) 2022 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _AARCH64_MORELLO_CHERI_PERMS_H
|
||||
#define _AARCH64_MORELLO_CHERI_PERMS_H
|
||||
|
||||
/* Capability permission bits. These are defined in the Arm Architecture
|
||||
Reference Manual Suplement- Morello for A-Profile Architecture:
|
||||
https://developer.arm.com/documentation/ddi0606/latest */
|
||||
#define CAP_PERM_LOAD (1 << 17)
|
||||
#define CAP_PERM_STORE (1 << 16)
|
||||
#define CAP_PERM_EXECUTE (1 << 15)
|
||||
#define CAP_PERM_LOAD_CAP (1 << 14)
|
||||
#define CAP_PERM_STORE_CAP (1 << 13)
|
||||
#define CAP_PERM_STORE_LOCAL (1 << 12)
|
||||
#define CAP_PERM_SEAL (1 << 11)
|
||||
#define CAP_PERM_UNSEAL (1 << 10)
|
||||
#define CAP_PERM_SYSTEM (1 << 9)
|
||||
#define CAP_PERM_BRANCH_SEALED_PAIR (1 << 8)
|
||||
#define CAP_PERM_COMPARTMENT_ID (1 << 7)
|
||||
#define CAP_PERM_MUTABLE_LOAD (1 << 6)
|
||||
#define CAP_PERM_EXECUTIVE (1 << 1)
|
||||
#define CAP_PERM_GLOBAL (1 << 0)
|
||||
|
||||
/* Used with __builtin_cheri_perms_and. */
|
||||
#define CAP_PERM_MASK_BASE (-1UL ^ ( \
|
||||
CAP_PERM_LOAD | \
|
||||
CAP_PERM_STORE | \
|
||||
CAP_PERM_EXECUTE | \
|
||||
CAP_PERM_LOAD_CAP | \
|
||||
CAP_PERM_MUTABLE_LOAD | \
|
||||
CAP_PERM_STORE_CAP | \
|
||||
CAP_PERM_STORE_LOCAL | \
|
||||
CAP_PERM_EXECUTIVE | \
|
||||
CAP_PERM_SYSTEM | \
|
||||
CAP_PERM_SEAL | \
|
||||
CAP_PERM_UNSEAL | \
|
||||
CAP_PERM_COMPARTMENT_ID))
|
||||
#define CAP_PERM_MASK_R ( \
|
||||
CAP_PERM_MASK_BASE | \
|
||||
CAP_PERM_LOAD | \
|
||||
CAP_PERM_LOAD_CAP | \
|
||||
CAP_PERM_MUTABLE_LOAD)
|
||||
#define CAP_PERM_MASK_RW ( \
|
||||
CAP_PERM_MASK_R | \
|
||||
CAP_PERM_STORE | \
|
||||
CAP_PERM_STORE_CAP | \
|
||||
CAP_PERM_STORE_LOCAL)
|
||||
#define CAP_PERM_MASK_RX ( \
|
||||
CAP_PERM_MASK_R | \
|
||||
CAP_PERM_EXECUTE | \
|
||||
CAP_PERM_EXECUTIVE | \
|
||||
CAP_PERM_SYSTEM)
|
||||
|
||||
#define STACK_CAP_PERM_PCS ( \
|
||||
CAP_PERM_LOAD | \
|
||||
CAP_PERM_STORE | \
|
||||
CAP_PERM_LOAD_CAP | \
|
||||
CAP_PERM_STORE_CAP | \
|
||||
CAP_PERM_MUTABLE_LOAD)
|
||||
|
||||
/* Check if stack is valid according to stack PCS rules. Only permissions
|
||||
are checked, seal and invalid tag cause fault on access. */
|
||||
#define STACK_CAP_CHECK(stack, size) \
|
||||
({unsigned long __perm = __builtin_cheri_perms_get (stack); \
|
||||
(__perm & (CAP_PERM_GLOBAL|CAP_PERM_STORE_LOCAL)) \
|
||||
&& (__perm & STACK_CAP_PERM_PCS) == STACK_CAP_PERM_PCS;})
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,93 @@
|
||||
/* Special .init and .fini section support for Morello.
|
||||
Copyright (C) 1995-2022 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
In addition to the permissions in the GNU Lesser General Public
|
||||
License, the Free Software Foundation gives you unlimited
|
||||
permission to link the compiled version of this file with other
|
||||
programs, and to distribute those programs without any restriction
|
||||
coming from the use of this file. (The GNU Lesser General Public
|
||||
License restrictions do apply in other respects; for example, they
|
||||
cover modification of the file, and distribution when not linked
|
||||
into another program.)
|
||||
|
||||
Note that people who make modified versions of this file are not
|
||||
obligated to grant this special exception for their modified
|
||||
versions; it is their choice whether to do so. The GNU Lesser
|
||||
General Public License gives permission to release a modified
|
||||
version without this exception; this exception also makes it
|
||||
possible to release a modified version which carries forward this
|
||||
exception.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* crti.S puts a function prologue at the beginning of the .init and
|
||||
.fini sections and defines global symbols for those addresses, so
|
||||
they can be called as functions. The symbols _init and _fini are
|
||||
magic and cause the linker to emit DT_INIT and DT_FINI. */
|
||||
|
||||
#include <sysdep.h>
|
||||
#include <libc-symbols.h>
|
||||
|
||||
#ifndef PREINIT_FUNCTION
|
||||
# define PREINIT_FUNCTION __gmon_start__
|
||||
#endif
|
||||
|
||||
#ifndef PREINIT_FUNCTION_WEAK
|
||||
# define PREINIT_FUNCTION_WEAK 1
|
||||
#endif
|
||||
|
||||
#if PREINIT_FUNCTION_WEAK
|
||||
weak_extern (PREINIT_FUNCTION)
|
||||
#else
|
||||
.hidden PREINIT_FUNCTION
|
||||
#endif
|
||||
|
||||
#if PREINIT_FUNCTION_WEAK
|
||||
.align 2
|
||||
.type call_weak_fn, %function
|
||||
call_weak_fn:
|
||||
adrp c0, :got:PREINIT_FUNCTION
|
||||
ldr c0, [c0, #:got_lo12:PREINIT_FUNCTION]
|
||||
cbz x0, 1f
|
||||
b PREINIT_FUNCTION
|
||||
1:
|
||||
RET
|
||||
.size call_weak_fn, .-call_weak_fn
|
||||
#endif
|
||||
|
||||
.section .init,"ax",%progbits
|
||||
.align 2
|
||||
.global _init
|
||||
.hidden _init
|
||||
.type _init, %function
|
||||
_init:
|
||||
stp c29, c30, [csp, -32]!
|
||||
mov c29, csp
|
||||
#if PREINIT_FUNCTION_WEAK
|
||||
bl call_weak_fn
|
||||
#else
|
||||
bl PREINIT_FUNCTION
|
||||
#endif
|
||||
|
||||
.section .fini,"ax",%progbits
|
||||
.align 2
|
||||
.global _fini
|
||||
.hidden _fini
|
||||
.type _fini, %function
|
||||
_fini:
|
||||
stp c29, c30, [csp, -32]!
|
||||
mov c29, csp
|
||||
@@ -0,0 +1,48 @@
|
||||
/* Special .init and .fini section support for Morello.
|
||||
Copyright (C) 1995-2022 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
In addition to the permissions in the GNU Lesser General Public
|
||||
License, the Free Software Foundation gives you unlimited
|
||||
permission to link the compiled version of this file with other
|
||||
programs, and to distribute those programs without any restriction
|
||||
coming from the use of this file. (The GNU Lesser General Public
|
||||
License restrictions do apply in other respects; for example, they
|
||||
cover modification of the file, and distribution when not linked
|
||||
into another program.)
|
||||
|
||||
Note that people who make modified versions of this file are not
|
||||
obligated to grant this special exception for their modified
|
||||
versions; it is their choice whether to do so. The GNU Lesser
|
||||
General Public License gives permission to release a modified
|
||||
version without this exception; this exception also makes it
|
||||
possible to release a modified version which carries forward this
|
||||
exception.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* crtn.S puts function epilogues in the .init and .fini sections
|
||||
corresponding to the prologues in crti.S. */
|
||||
|
||||
#include <sysdep.h>
|
||||
|
||||
.section .init,"ax",%progbits
|
||||
ldp c29, c30, [csp], 32
|
||||
RET
|
||||
|
||||
.section .fini,"ax",%progbits
|
||||
ldp c29, c30, [csp], 32
|
||||
RET
|
||||
@@ -0,0 +1,68 @@
|
||||
/* Machine-dependent ELF indirect relocation inline functions.
|
||||
AArch64 version.
|
||||
Copyright (C) 2012-2022 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _DL_IREL_H
|
||||
#define _DL_IREL_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <ldsodefs.h>
|
||||
#include <sysdep.h>
|
||||
#include <sys/ifunc.h>
|
||||
|
||||
#define ELF_MACHINE_IRELA 1
|
||||
|
||||
static inline uintptr_t
|
||||
__attribute ((always_inline))
|
||||
elf_ifunc_invoke (uintptr_t addr)
|
||||
{
|
||||
__ifunc_arg_t arg;
|
||||
|
||||
arg._size = sizeof (arg);
|
||||
arg._hwcap = GLRO(dl_hwcap);
|
||||
arg._hwcap2 = GLRO(dl_hwcap2);
|
||||
return ((uintptr_t (*) (uint64_t, const __ifunc_arg_t *)) (addr))
|
||||
(GLRO(dl_hwcap) | _IFUNC_ARG_HWCAP, &arg);
|
||||
}
|
||||
|
||||
#include <cheri-rel.h>
|
||||
|
||||
static inline void
|
||||
__attribute ((always_inline))
|
||||
elf_irela (const ElfW(Rela) *reloc)
|
||||
{
|
||||
const unsigned long int r_type = ELFW(R_TYPE) (reloc->r_info);
|
||||
|
||||
if (__glibc_likely (r_type == MORELLO_R(IRELATIVE)))
|
||||
{
|
||||
struct link_map *main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
|
||||
void *reloc_addr = (void *) dl_rw_ptr (main_map, reloc->r_offset);
|
||||
uintptr_t *__attribute__((may_alias)) cap_reloc_addr = reloc_addr;
|
||||
uint64_t base = main_map->l_addr;
|
||||
uintptr_t cap_rx = main_map->l_map_start;
|
||||
uintptr_t cap_rw = main_map->l_rw_start;
|
||||
uintptr_t value
|
||||
= morello_relative (base, cap_rx, cap_rw, reloc, reloc_addr);
|
||||
*cap_reloc_addr = elf_ifunc_invoke (value);
|
||||
}
|
||||
else
|
||||
__libc_fatal ("Unexpected reloc type in static binary.\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,473 @@
|
||||
/* Copyright (C) 1995-2022 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public License as
|
||||
published by the Free Software Foundation; either version 2.1 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef dl_machine_h
|
||||
#define dl_machine_h
|
||||
|
||||
#define ELF_MACHINE_NAME "aarch64"
|
||||
|
||||
#include <sysdep.h>
|
||||
#include <tls.h>
|
||||
#include <dl-tlsdesc.h>
|
||||
#include <dl-static-tls.h>
|
||||
#include <dl-irel.h>
|
||||
#include <dl-machine-rel.h>
|
||||
#include <cpu-features.c>
|
||||
|
||||
/* Translate a processor specific dynamic tag to the index in l_info array. */
|
||||
#define DT_AARCH64(x) (DT_AARCH64_##x - DT_LOPROC + DT_NUM)
|
||||
|
||||
/* Return nonzero iff ELF header is compatible with the running host. */
|
||||
static inline int __attribute__ ((unused))
|
||||
elf_machine_matches_host (const ElfW(Ehdr) *ehdr)
|
||||
{
|
||||
return ehdr->e_machine == EM_AARCH64
|
||||
&& (ehdr->e_flags & EF_AARCH64_CHERI_PURECAP) != 0;
|
||||
}
|
||||
|
||||
/* Set up the loaded object described by L so its unrelocated PLT
|
||||
entries will jump to the on-demand fixup code in dl-runtime.c. */
|
||||
|
||||
static inline int __attribute__ ((unused))
|
||||
elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
|
||||
int lazy, int profile)
|
||||
{
|
||||
if (l->l_info[DT_JMPREL] && lazy)
|
||||
{
|
||||
uintptr_t *got;
|
||||
extern void _dl_runtime_resolve (ElfW(Word));
|
||||
extern void _dl_runtime_profile (ElfW(Word));
|
||||
|
||||
got = (uintptr_t *) D_PTR_RW (l, l_info[DT_PLTGOT]);
|
||||
if (got[1])
|
||||
{
|
||||
l->l_mach.plt = dl_rx_ptr (l, got[1]);
|
||||
}
|
||||
got[1] = (uintptr_t) l;
|
||||
|
||||
/* The got[2] entry contains the address of a function which gets
|
||||
called to get the address of a so far unresolved function and
|
||||
jump to it. The profiling extension of the dynamic linker allows
|
||||
to intercept the calls to collect information. In this case we
|
||||
don't store the address in the GOT so that all future calls also
|
||||
end in this function. */
|
||||
if ( profile)
|
||||
{
|
||||
got[2] = (uintptr_t) &_dl_runtime_profile;
|
||||
|
||||
if (GLRO(dl_profile) != NULL
|
||||
&& _dl_name_match_p (GLRO(dl_profile), l))
|
||||
/* Say that we really want profiling and the timers are
|
||||
started. */
|
||||
GL(dl_profile_map) = l;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This function will get called to fix up the GOT entry
|
||||
indicated by the offset on the stack, and then jump to
|
||||
the resolved address. */
|
||||
got[2] = (uintptr_t) &_dl_runtime_resolve;
|
||||
}
|
||||
}
|
||||
|
||||
return lazy;
|
||||
}
|
||||
|
||||
/* Runtime _DYNAMIC without dynamic relocations. */
|
||||
static void * __attribute__ ((unused))
|
||||
elf_machine_runtime_dynamic (void)
|
||||
{
|
||||
void *p;
|
||||
asm (""
|
||||
".weak _DYNAMIC\n"
|
||||
".hidden _DYNAMIC\n"
|
||||
"adrp %0, _DYNAMIC\n"
|
||||
"add %0, %0, :lo12:_DYNAMIC\n" : "=r"(p));
|
||||
return p;
|
||||
}
|
||||
|
||||
/* PCC relative access to ehdr before relocations are processed. */
|
||||
static const ElfW(Ehdr) *
|
||||
elf_machine_ehdr (void)
|
||||
{
|
||||
const void *p;
|
||||
asm (""
|
||||
".weak __ehdr_start\n"
|
||||
".hidden __ehdr_start\n"
|
||||
"adrp %0, __ehdr_start\n"
|
||||
"add %0, %0, :lo12:__ehdr_start\n" : "=r"(p));
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Set up ld.so root capabilities and base address from args. */
|
||||
static void __attribute__ ((unused))
|
||||
elf_machine_rtld_base_setup (struct link_map *map, void *args)
|
||||
{
|
||||
uintptr_t *sp;
|
||||
long argc;
|
||||
uintptr_t cap_rx, cap_rw, cap_exe_rx, cap_exe_rw;
|
||||
unsigned long ldso_base = 0;
|
||||
|
||||
sp = args;
|
||||
argc = sp[0];
|
||||
/* Skip argv. */
|
||||
sp += argc + 2;
|
||||
/* Skip environ. */
|
||||
for (; *sp; sp++);
|
||||
sp++;
|
||||
cap_rx = cap_rw = cap_exe_rx = cap_exe_rw = 0;
|
||||
for (; *sp != AT_NULL; sp += 2)
|
||||
{
|
||||
long t = sp[0];
|
||||
if (t == AT_BASE)
|
||||
ldso_base = sp[1];
|
||||
if (t == AT_CHERI_INTERP_RX_CAP)
|
||||
cap_rx = sp[1];
|
||||
if (t == AT_CHERI_INTERP_RW_CAP)
|
||||
cap_rw = sp[1];
|
||||
if (t == AT_CHERI_EXEC_RX_CAP)
|
||||
cap_exe_rx = sp[1];
|
||||
if (t == AT_CHERI_EXEC_RW_CAP)
|
||||
cap_exe_rw = sp[1];
|
||||
}
|
||||
/* Check if ldso is the executable. */
|
||||
if (ldso_base == 0)
|
||||
{
|
||||
cap_rx = cap_exe_rx;
|
||||
cap_rw = cap_exe_rw;
|
||||
ldso_base = cap_rx; /* Assume load segments start at vaddr 0. */
|
||||
}
|
||||
cap_rx = __builtin_cheri_perms_and (cap_rx, CAP_PERM_MASK_RX);
|
||||
cap_rw = __builtin_cheri_perms_and (cap_rw, CAP_PERM_MASK_RW);
|
||||
map->l_addr = ldso_base;
|
||||
map->l_map_start = cap_rx;
|
||||
map->l_rw_start = cap_rw;
|
||||
|
||||
/* Set up the RW ranges of ld.so, required for symbolic relocations. */
|
||||
const ElfW(Ehdr) *ehdr = elf_machine_ehdr ();
|
||||
const ElfW(Phdr) *phdr = (const void *) ehdr + ehdr->e_phoff;
|
||||
if (sizeof *phdr != ehdr->e_phentsize)
|
||||
__builtin_trap ();
|
||||
for (const ElfW(Phdr) *ph = phdr; ph < phdr + ehdr->e_phnum; ph++)
|
||||
if (ph->p_type == PT_LOAD && (ph->p_flags & PF_W))
|
||||
{
|
||||
uintptr_t allocend = map->l_addr + ph->p_vaddr + ph->p_memsz;
|
||||
if (map->l_rw_count >= DL_MAX_RW_COUNT)
|
||||
__builtin_trap ();
|
||||
map->l_rw_range[map->l_rw_count].start = map->l_addr + ph->p_vaddr;
|
||||
map->l_rw_range[map->l_rw_count].end = allocend;
|
||||
map->l_rw_count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* In elf/rtld.c _dl_start should be global so dl-start.S can reference it. */
|
||||
#define RTLD_START asm (".globl _dl_start");
|
||||
|
||||
#define elf_machine_type_class(type) \
|
||||
(((type) == MORELLO_R(JUMP_SLOT) \
|
||||
|| (type) == MORELLO_R(TPREL128) \
|
||||
|| (type) == MORELLO_R(TLSDESC)) * ELF_RTYPE_CLASS_PLT)
|
||||
|
||||
#define ELF_MACHINE_JMP_SLOT MORELLO_R(JUMP_SLOT)
|
||||
|
||||
#define DL_PLATFORM_INIT dl_platform_init ()
|
||||
|
||||
static inline void __attribute__ ((unused))
|
||||
dl_platform_init (void)
|
||||
{
|
||||
if (GLRO(dl_platform) != NULL && *GLRO(dl_platform) == '\0')
|
||||
/* Avoid an empty string which would disturb us. */
|
||||
GLRO(dl_platform) = NULL;
|
||||
|
||||
#ifdef SHARED
|
||||
/* init_cpu_features has been called early from __libc_start_main in
|
||||
static executable. */
|
||||
init_cpu_features (&GLRO(dl_aarch64_cpu_features));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static inline uintptr_t
|
||||
elf_machine_fixup_plt (struct link_map *map, lookup_t t,
|
||||
const ElfW(Sym) *refsym, const ElfW(Sym) *sym,
|
||||
const ElfW(Rela) *reloc,
|
||||
uintptr_t *reloc_addr,
|
||||
uintptr_t value)
|
||||
{
|
||||
return *reloc_addr = value;
|
||||
}
|
||||
|
||||
/* Return the final value of a plt relocation. */
|
||||
static inline uintptr_t
|
||||
elf_machine_plt_value (struct link_map *map,
|
||||
const ElfW(Rela) *reloc,
|
||||
uintptr_t value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Names of the architecture-specific auditing callback functions. */
|
||||
#define ARCH_LA_PLTENTER aarch64_gnu_pltenter
|
||||
#define ARCH_LA_PLTEXIT aarch64_gnu_pltexit
|
||||
|
||||
#ifdef RESOLVE_MAP
|
||||
|
||||
# include <cheri_perms.h>
|
||||
|
||||
static inline void
|
||||
__attribute__ ((always_inline))
|
||||
elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
|
||||
const ElfW(Rela) *reloc, const ElfW(Sym) *sym,
|
||||
const struct r_found_version *version,
|
||||
void *const reloc_addr, int skip_ifunc)
|
||||
{
|
||||
uint64_t *__attribute__((may_alias)) u64_reloc_addr = reloc_addr;
|
||||
uintptr_t *__attribute__((may_alias)) cap_reloc_addr = reloc_addr;
|
||||
const unsigned int r_type = ELFW (R_TYPE) (reloc->r_info);
|
||||
|
||||
if (r_type == MORELLO_R(RELATIVE))
|
||||
*cap_reloc_addr = morello_relative (map->l_addr, map->l_map_start,
|
||||
map->l_rw_start, reloc, reloc_addr);
|
||||
else if (r_type == AARCH64_R(RELATIVE))
|
||||
*u64_reloc_addr = map->l_addr + reloc->r_addend;
|
||||
else if (__builtin_expect (r_type == R_AARCH64_NONE, 0))
|
||||
return;
|
||||
else
|
||||
{
|
||||
struct link_map *sym_map = RESOLVE_MAP (map, scope, &sym, version,
|
||||
r_type);
|
||||
uintptr_t value = SYMBOL_ADDRESS (sym_map, sym, true);
|
||||
|
||||
if (sym != NULL
|
||||
&& __glibc_unlikely (ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC)
|
||||
&& __glibc_likely (sym->st_shndx != SHN_UNDEF)
|
||||
&& __glibc_likely (!skip_ifunc))
|
||||
value = elf_ifunc_invoke (value);
|
||||
|
||||
switch (r_type)
|
||||
{
|
||||
case MORELLO_R(CAPINIT):
|
||||
case MORELLO_R(GLOB_DAT):
|
||||
case MORELLO_R(JUMP_SLOT):
|
||||
{
|
||||
if (sym == NULL)
|
||||
{
|
||||
/* Undefined weak symbol. */
|
||||
*cap_reloc_addr = value + reloc->r_addend;
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned long perm_mask = CAP_PERM_MASK_RX;
|
||||
switch (ELFW(ST_TYPE) (sym->st_info))
|
||||
{
|
||||
case STT_OBJECT:
|
||||
perm_mask = CAP_PERM_MASK_R;
|
||||
for (int i = 0; i < sym_map->l_rw_count; i++)
|
||||
if (sym_map->l_rw_range[i].start <= value
|
||||
&& sym_map->l_rw_range[i].end > value)
|
||||
{
|
||||
value = dl_rw_ptr (sym_map, value - sym_map->l_addr);
|
||||
perm_mask = CAP_PERM_MASK_RW;
|
||||
break;
|
||||
}
|
||||
value = __builtin_cheri_bounds_set_exact (value, sym->st_size);
|
||||
break;
|
||||
case STT_FUNC:
|
||||
case STT_GNU_IFUNC:
|
||||
/* value already has RX bounds. */
|
||||
break;
|
||||
default:
|
||||
/* STT_NONE or unknown symbol: readonly. */
|
||||
perm_mask = CAP_PERM_MASK_R;
|
||||
}
|
||||
value = value + reloc->r_addend;
|
||||
value = __builtin_cheri_perms_and (value, perm_mask);
|
||||
|
||||
/* Seal capabilities, which provide execute permission, with MORELLO_RB. */
|
||||
if (perm_mask == CAP_PERM_MASK_RX)
|
||||
value = __builtin_cheri_seal_entry (value);
|
||||
|
||||
*cap_reloc_addr = value;
|
||||
}
|
||||
break;
|
||||
|
||||
# ifndef RTLD_BOOTSTRAP
|
||||
case AARCH64_R(ABS64):
|
||||
*u64_reloc_addr = value + reloc->r_addend;
|
||||
break;
|
||||
|
||||
case MORELLO_R(IRELATIVE):
|
||||
{
|
||||
uintptr_t value = morello_relative (map->l_addr,
|
||||
map->l_map_start,
|
||||
map->l_rw_start,
|
||||
reloc,
|
||||
reloc_addr);
|
||||
if (__glibc_likely (!skip_ifunc))
|
||||
value = elf_ifunc_invoke (value);
|
||||
*cap_reloc_addr = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case MORELLO_R(TLSDESC):
|
||||
{
|
||||
struct tlsdesc volatile *td = reloc_addr;
|
||||
if (! sym)
|
||||
{
|
||||
td->pair.off = reloc->r_addend;
|
||||
td->entry = _dl_tlsdesc_undefweak;
|
||||
}
|
||||
else
|
||||
{
|
||||
# ifndef SHARED
|
||||
CHECK_STATIC_TLS (map, sym_map);
|
||||
# else
|
||||
if (!TRY_STATIC_TLS (map, sym_map))
|
||||
{
|
||||
size_t size = td->pair.size;
|
||||
if (size == 0)
|
||||
size = sym->st_size;
|
||||
struct tlsdesc_dynamic_arg *arg = _dl_make_tlsdesc_dynamic
|
||||
(sym_map, sym->st_value + reloc->r_addend);
|
||||
arg->tlsinfo.ti_size = size;
|
||||
td->arg = arg;
|
||||
td->entry = _dl_tlsdesc_dynamic;
|
||||
}
|
||||
else
|
||||
# endif
|
||||
{
|
||||
td->pair.off = sym->st_value + sym_map->l_tls_offset
|
||||
+ reloc->r_addend;
|
||||
if (td->pair.size == 0)
|
||||
td->pair.size = sym->st_size;
|
||||
td->entry = _dl_tlsdesc_return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MORELLO_R(TPREL128):
|
||||
{
|
||||
CHECK_STATIC_TLS (map, sym_map);
|
||||
u64_reloc_addr[0] = sym->st_value + reloc->r_addend
|
||||
+ sym_map->l_tls_offset;
|
||||
if (u64_reloc_addr[1] == 0)
|
||||
u64_reloc_addr[1] = sym->st_size;
|
||||
}
|
||||
break;
|
||||
# endif /* !RTLD_BOOTSTRAP */
|
||||
default:
|
||||
_dl_reloc_bad_type (map, r_type, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
__attribute__ ((always_inline))
|
||||
elf_machine_rela_relative (struct link_map *map, const ElfW(Rela) *reloc)
|
||||
{
|
||||
ElfW(Addr) l_addr = map->l_addr;
|
||||
uintptr_t cap_rx = map->l_map_start;
|
||||
uintptr_t cap_rw = map->l_rw_start;
|
||||
void *const reloc_addr
|
||||
= (void *) __builtin_cheri_address_set (cap_rw, l_addr + reloc->r_offset);
|
||||
uint64_t *__attribute__((may_alias)) u64_reloc_addr = reloc_addr;
|
||||
uintptr_t *__attribute__((may_alias)) cap_reloc_addr = reloc_addr;
|
||||
const unsigned int r_type = ELFW (R_TYPE) (reloc->r_info);
|
||||
if (r_type == MORELLO_R(RELATIVE))
|
||||
*cap_reloc_addr = morello_relative (l_addr, cap_rx, cap_rw,
|
||||
reloc, reloc_addr);
|
||||
else
|
||||
*u64_reloc_addr = l_addr + reloc->r_addend;
|
||||
}
|
||||
|
||||
static inline void
|
||||
__attribute__ ((always_inline))
|
||||
elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
ElfW(Addr) l_addr,
|
||||
const ElfW(Rela) *reloc,
|
||||
int skip_ifunc)
|
||||
{
|
||||
void *reloc_addr = (void *) dl_rw_ptr (map, reloc->r_offset);
|
||||
uintptr_t *__attribute__((may_alias)) cap_reloc_addr = reloc_addr;
|
||||
const unsigned int r_type = ELFW (R_TYPE) (reloc->r_info);
|
||||
/* Check for unexpected PLT reloc type. */
|
||||
if (__builtin_expect (r_type == MORELLO_R(JUMP_SLOT), 1))
|
||||
{
|
||||
if (__glibc_unlikely (map->l_info[DT_AARCH64 (VARIANT_PCS)] != NULL))
|
||||
{
|
||||
/* Check the symbol table for variant PCS symbols. */
|
||||
const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
|
||||
const ElfW (Sym) *symtab =
|
||||
(const void *)D_PTR (map, l_info[DT_SYMTAB]);
|
||||
const ElfW (Sym) *sym = &symtab[symndx];
|
||||
if (__glibc_unlikely (sym->st_other & STO_AARCH64_VARIANT_PCS))
|
||||
{
|
||||
/* Avoid lazy resolution of variant PCS symbols. */
|
||||
const struct r_found_version *version = NULL;
|
||||
if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
|
||||
{
|
||||
const ElfW (Half) *vernum =
|
||||
(const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
|
||||
version = &map->l_versions[vernum[symndx] & 0x7fff];
|
||||
}
|
||||
elf_machine_rela (map, scope, reloc, sym, version, reloc_addr,
|
||||
skip_ifunc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (map->l_mach.plt == 0)
|
||||
*cap_reloc_addr = dl_rx_ptr (map, *cap_reloc_addr);
|
||||
else
|
||||
*cap_reloc_addr = map->l_mach.plt;
|
||||
}
|
||||
else if (__builtin_expect (r_type == MORELLO_R(TLSDESC), 1))
|
||||
{
|
||||
const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
|
||||
const ElfW (Sym) *symtab = (const void *)D_PTR (map, l_info[DT_SYMTAB]);
|
||||
const ElfW (Sym) *sym = &symtab[symndx];
|
||||
const struct r_found_version *version = NULL;
|
||||
|
||||
if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
|
||||
{
|
||||
const ElfW (Half) *vernum =
|
||||
(const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
|
||||
version = &map->l_versions[vernum[symndx] & 0x7fff];
|
||||
}
|
||||
|
||||
/* Always initialize TLS descriptors completely, because lazy
|
||||
initialization requires synchronization at every TLS access. */
|
||||
elf_machine_rela (map, scope, reloc, sym, version, reloc_addr,
|
||||
skip_ifunc);
|
||||
}
|
||||
else if (__glibc_unlikely (r_type == MORELLO_R(IRELATIVE)))
|
||||
{
|
||||
uintptr_t value = morello_relative (map->l_addr, map->l_map_start,
|
||||
map->l_rw_start, reloc, reloc_addr);
|
||||
if (__glibc_likely (!skip_ifunc))
|
||||
value = elf_ifunc_invoke (value);
|
||||
*cap_reloc_addr = value;
|
||||
}
|
||||
else
|
||||
_dl_reloc_bad_type (map, r_type, 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,61 @@
|
||||
/* Function to access r_debug structure. Morello version.
|
||||
Copyright (C) 2022 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, see
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <link.h>
|
||||
|
||||
static int
|
||||
E(callback) (struct dl_phdr_info *info, size_t size, void *data)
|
||||
{
|
||||
/* Assume phdr covers the load segments. */
|
||||
const void *phdr = info->dlpi_phdr;
|
||||
uintptr_t *p = data;
|
||||
unsigned long addr = *p;
|
||||
unsigned long base = __builtin_cheri_base_get (phdr);
|
||||
unsigned long len = __builtin_cheri_length_get (phdr);
|
||||
if (addr - base >= len)
|
||||
return 0;
|
||||
*p = __builtin_cheri_address_set ((uintptr_t) phdr, addr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return a valid runtime pointer to r_debug instead of an address since
|
||||
that's how this function is used despite its generic prototype.
|
||||
Assume the lookup is for the main exe and return uintptr_t type. */
|
||||
|
||||
static inline uintptr_t
|
||||
E(r_debug_address) (ElfW(Dyn) *d)
|
||||
{
|
||||
if (d->d_tag != DT_DEBUG)
|
||||
return 0;
|
||||
uintptr_t p = d->d_un.d_ptr;
|
||||
if (dl_iterate_phdr (E(callback), &p) == 1)
|
||||
return p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the offset of the struct r_debug before relocation. */
|
||||
|
||||
static inline EW(Addr)
|
||||
E(r_debug_offset) (EW(Dyn) *d, int fd, EW(Addr) offset)
|
||||
{
|
||||
if (d->d_tag == DT_DEBUG)
|
||||
return (EW(Addr)) d->d_un.d_ptr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user