mirror of
git://sourceware.org/git/glibc.git
synced 2026-09-09 11:58:23 +08:00
Compare commits
113
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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. */
|
||||
|
||||
+2
-2
@@ -139,8 +139,8 @@ call_init (int argc, char **argv, char **env)
|
||||
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 *) (init_array->d_un.d_ptr + l->l_addr);
|
||||
for (unsigned int j = 0; j < jm; ++j)
|
||||
((dl_init_t) addrs[j]) (argc, argv, env);
|
||||
}
|
||||
|
||||
+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 = phdr->p_vaddr + (void *) main_map->l_addr;
|
||||
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);
|
||||
|
||||
+3
-3
@@ -119,11 +119,11 @@ call_destructors (void *closure)
|
||||
|
||||
if (map->l_info[DT_FINI_ARRAY] != NULL)
|
||||
{
|
||||
ElfW(Addr) *array =
|
||||
(ElfW(Addr) *) (map->l_addr
|
||||
elfptr_t *array =
|
||||
(elfptr_t *) (map->l_addr
|
||||
+ 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]) ();
|
||||
|
||||
+3
-3
@@ -133,11 +133,11 @@ _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
|
||||
elfptr_t *array =
|
||||
(elfptr_t *) (l->l_addr
|
||||
+ l->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
|
||||
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]) ();
|
||||
}
|
||||
|
||||
+6
-6
@@ -61,11 +61,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 *) (init_array->d_un.d_ptr + l->l_addr);
|
||||
for (j = 0; j < jm; ++j)
|
||||
((dl_init_t) addrs[j]) (argc, argv, env);
|
||||
}
|
||||
@@ -88,16 +88,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 *) (preinit_array->d_un.d_ptr + main_map->l_addr);
|
||||
for (cnt = 0; cnt < i; ++cnt)
|
||||
((dl_init_t) addrs[cnt]) (argc, argv, env);
|
||||
}
|
||||
|
||||
+1
-1
@@ -1369,7 +1369,7 @@ 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 = (ElfW(Addr)) l->l_tls_initimage + (char *) l->l_addr;
|
||||
|
||||
/* Process program headers again after load segments are mapped in
|
||||
case processing requires accessing those segments. Scan program
|
||||
|
||||
+21
-9
@@ -21,12 +21,12 @@
|
||||
|
||||
/* 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,
|
||||
MAP_COPY|MAP_FILE, fd, c->mapoff);
|
||||
|
||||
/* If the segment alignment > the page size, allocate enough space to
|
||||
@@ -34,15 +34,15 @@ _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,
|
||||
elfptr_t map_start = (elfptr_t) __mmap ((void *) mappref, maplen,
|
||||
PROT_NONE,
|
||||
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,
|
||||
elfptr_t map_start_aligned = ALIGN_UP (map_start, c->mapalign);
|
||||
map_start_aligned = (elfptr_t) __mmap ((void *) map_start_aligned,
|
||||
maplength, c->prot,
|
||||
MAP_COPY|MAP_FILE|MAP_FIXED,
|
||||
fd, c->mapoff);
|
||||
@@ -54,7 +54,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)
|
||||
@@ -126,6 +126,18 @@ _dl_map_segments (struct link_map *l, int fd,
|
||||
|
||||
goto postmap;
|
||||
}
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
else
|
||||
{
|
||||
/* TODO: l_addr is 0 in an exe, but it should cover the load segments. */
|
||||
uintptr_t l_addr = 0;
|
||||
unsigned long allocend = ALIGN_UP (loadcmds[nloadcmds - 1].allocend,
|
||||
GLRO(dl_pagesize));
|
||||
asm volatile ("cvtd %0, %x0" : "+r"(l_addr));
|
||||
asm volatile ("scbnds %0, %0, %x1" : "+r"(l_addr) : "r"(allocend));
|
||||
l->l_addr = l_addr;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Remember which part of the address space this object uses. */
|
||||
l->l_map_start = c->mapstart + l->l_addr;
|
||||
@@ -134,10 +146,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,
|
||||
c->dataend - c->mapstart, c->prot,
|
||||
MAP_FIXED|MAP_COPY|MAP_FILE,
|
||||
fd, c->mapoff)
|
||||
== MAP_FAILED))
|
||||
@@ -150,7 +162,7 @@ _dl_map_segments (struct link_map *l, int fd,
|
||||
{
|
||||
/* 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;
|
||||
zeroend = l->l_addr + c->allocend;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -353,10 +353,10 @@ _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
|
||||
elfptr_t start = ALIGN_DOWN((l->l_addr
|
||||
+ l->l_relro_addr),
|
||||
GLRO(dl_pagesize));
|
||||
ElfW(Addr) end = ALIGN_DOWN((l->l_addr
|
||||
elfptr_t end = ALIGN_DOWN((l->l_addr
|
||||
+ l->l_relro_addr
|
||||
+ l->l_relro_size),
|
||||
GLRO(dl_pagesize));
|
||||
|
||||
@@ -248,6 +248,14 @@ _dl_aux_init (ElfW(auxv_t) *av)
|
||||
GL(dl_sysinfo) = DL_SYSINFO_DEFAULT;
|
||||
#endif
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
/* Base is 0 in non-pie static executable, but it needs to be a valid
|
||||
capability. Use the zero capability instead of AT_BASE. */
|
||||
elfptr_t zerocap;
|
||||
asm volatile ("cvtd %0,xzr" : "=r"(zerocap));
|
||||
_dl_main_map.l_addr = zerocap;
|
||||
#endif
|
||||
|
||||
_dl_auxv = av;
|
||||
dl_parse_auxv_t auxv_values;
|
||||
/* Use an explicit initialization loop here because memset may not
|
||||
|
||||
+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);
|
||||
}
|
||||
|
||||
+2
-2
@@ -41,14 +41,14 @@
|
||||
|
||||
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)
|
||||
{
|
||||
const ElfW(Rel) *relative = (const void *) reladdr;
|
||||
const ElfW(Rel) *r = relative + nrelative;
|
||||
const ElfW(Rel) *end = (const void *) (reladdr + relsize);
|
||||
ElfW(Addr) l_addr = map->l_addr;
|
||||
elfptr_t l_addr = map->l_addr;
|
||||
const ElfW(Sym) *const symtab
|
||||
= (const void *) D_PTR (map, l_info[DT_SYMTAB]);
|
||||
|
||||
|
||||
+6
-6
@@ -37,7 +37,7 @@ elf_machine_rel (struct link_map *map, struct r_scope_elem *scope[],
|
||||
const struct r_found_version *version,
|
||||
void *const reloc_addr, int skip_ifunc);
|
||||
static inline void __attribute__((always_inline))
|
||||
elf_machine_rel_relative (ElfW(Addr) l_addr, const ElfW(Rel) *reloc,
|
||||
elf_machine_rel_relative (elfptr_t l_addr, const ElfW(Rel) *reloc,
|
||||
void *const reloc_addr);
|
||||
# endif
|
||||
# if ! ELF_MACHINE_NO_RELA
|
||||
@@ -47,18 +47,18 @@ elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
|
||||
const struct r_found_version *version, void *const reloc_addr,
|
||||
int skip_ifunc);
|
||||
static inline void __attribute__((always_inline))
|
||||
elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
|
||||
elf_machine_rela_relative (elfptr_t l_addr, const ElfW(Rela) *reloc,
|
||||
void *const reloc_addr);
|
||||
# endif
|
||||
# if ELF_MACHINE_NO_RELA || defined ELF_MACHINE_PLT_REL
|
||||
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(Rel) *reloc,
|
||||
elfptr_t l_addr, const ElfW(Rel) *reloc,
|
||||
int skip_ifunc);
|
||||
# else
|
||||
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,
|
||||
elfptr_t l_addr, const ElfW(Rela) *reloc,
|
||||
int skip_ifunc);
|
||||
# endif
|
||||
#endif
|
||||
@@ -80,7 +80,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 +97,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,12 @@ 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_SEAL_CAP 64
|
||||
|
||||
/* Note section contents. Each entry in the note section begins with
|
||||
a header of a fixed form. */
|
||||
|
||||
@@ -2906,6 +2921,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 +2933,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");
|
||||
|
||||
+13
-8
@@ -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,10 +446,10 @@ 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
|
||||
{
|
||||
@@ -515,7 +515,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 +542,16 @@ _dl_start (void *arg)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __CHERI_PURE_CAPABILITY__
|
||||
bootstrap_map.l_addr = elf_machine_load_address_from_args (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);
|
||||
|
||||
@@ -1152,7 +1157,7 @@ rtld_setup_main_map (struct link_map *main_map)
|
||||
{
|
||||
case PT_PHDR:
|
||||
/* Find out the load address. */
|
||||
main_map->l_addr = (ElfW(Addr)) phdr - ph->p_vaddr;
|
||||
main_map->l_addr = (elfptr_t) phdr - ph->p_vaddr;
|
||||
break;
|
||||
case PT_DYNAMIC:
|
||||
/* This tells us where to find the dynamic section,
|
||||
@@ -1274,7 +1279,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;
|
||||
= (ElfW(Addr)) main_map->l_tls_initimage + (char *) main_map->l_addr;
|
||||
if (! main_map->l_map_end)
|
||||
main_map->l_map_end = ~0;
|
||||
if (! main_map->l_text_end)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)) \
|
||||
|
||||
@@ -426,8 +426,12 @@ for linking")
|
||||
|
||||
#define attribute_tls_model_ie __attribute__ ((tls_model ("initial-exec")))
|
||||
|
||||
#if defined __CHERI_PURE_CAPABILITY__
|
||||
/* avoid readonly caps at startup when relro has to be writable */
|
||||
#define attribute_relro
|
||||
#else
|
||||
#define attribute_relro __attribute__ ((section (".data.rel.ro")))
|
||||
|
||||
#endif
|
||||
|
||||
/* Used to disable stack protection in sensitive places, like ifunc
|
||||
resolvers and early static TLS init. */
|
||||
|
||||
+6
-5
@@ -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
|
||||
elfptr_t 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. */
|
||||
@@ -252,9 +253,9 @@ 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, l_map_end;
|
||||
/* End of the executable part of the mapping. */
|
||||
ElfW(Addr) l_text_end;
|
||||
elfptr_t l_text_end;
|
||||
|
||||
/* Default array for 'l_scope'. */
|
||||
struct r_scope_elem *l_scope_mem[4];
|
||||
@@ -343,7 +344,7 @@ struct link_map
|
||||
|
||||
/* Information used to change permission after the relocations are
|
||||
done. */
|
||||
ElfW(Addr) l_relro_addr;
|
||||
elfptr_t l_relro_addr;
|
||||
size_t l_relro_size;
|
||||
|
||||
unsigned long long int l_serial;
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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. */
|
||||
|
||||
+3
-3
@@ -444,7 +444,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 +518,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)
|
||||
@@ -760,7 +760,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;
|
||||
|
||||
+5
-2
@@ -341,8 +341,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)
|
||||
|
||||
/*
|
||||
@@ -4978,8 +4982,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;
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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. */
|
||||
};
|
||||
|
||||
@@ -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,8 @@ 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. */
|
||||
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 +1333,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 +1350,7 @@ 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;
|
||||
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');
|
||||
|
||||
@@ -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);
|
||||
|
||||
+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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -28,6 +28,7 @@ typedef union
|
||||
} La_aarch64_vector;
|
||||
|
||||
/* Registers for entry into PLT on AArch64. */
|
||||
#ifndef __CHERI_PURE_CAPABILITY__
|
||||
typedef struct La_aarch64_regs
|
||||
{
|
||||
uint64_t lr_xreg[9];
|
||||
@@ -46,6 +47,24 @@ typedef struct La_aarch64_retval
|
||||
La_aarch64_vector lrv_vreg[8];
|
||||
void *lrv_vpcs;
|
||||
} La_aarch64_retval;
|
||||
#else
|
||||
typedef struct La_aarch64_regs
|
||||
{
|
||||
uintptr_t lr_xreg[9];
|
||||
La_aarch64_vector lr_vreg[8];
|
||||
uintptr_t lr_sp;
|
||||
uintptr_t lr_lr;
|
||||
void *lr_vpcs;
|
||||
} La_aarch64_regs;
|
||||
|
||||
typedef struct La_aarch64_retval
|
||||
{
|
||||
uintptr_t lrv_xreg[8];
|
||||
La_aarch64_vector lrv_vreg[8];
|
||||
void *lrv_vpcs;
|
||||
} La_aarch64_retval;
|
||||
#endif
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
extern ElfW(Addr)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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,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,66 @@
|
||||
/* 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_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_STORE_CAP | \
|
||||
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)
|
||||
#define CAP_PERM_MASK_RW (CAP_PERM_MASK_R | CAP_PERM_STORE | CAP_PERM_STORE_CAP)
|
||||
#define CAP_PERM_MASK_RX (CAP_PERM_MASK_R | CAP_PERM_EXECUTE)
|
||||
|
||||
#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,100 @@
|
||||
/* 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_perms.h>
|
||||
|
||||
static inline uintptr_t
|
||||
__attribute__ ((always_inline))
|
||||
morello_relative_value (uintptr_t l_addr,
|
||||
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;
|
||||
unsigned long perm_mask = 0;
|
||||
uintptr_t value = __builtin_cheri_bounds_set_exact (l_addr + loc, len);
|
||||
|
||||
value = value + reloc->r_addend;
|
||||
|
||||
/* Set permissions. Permissions field encoded as:
|
||||
4 = executable, 2 = read/write, 1 = read-only.
|
||||
Mask should follow the same encoding as the ELF segment permissions. */
|
||||
if (perm == 1)
|
||||
perm_mask = CAP_PERM_MASK_R;
|
||||
if (perm == 2)
|
||||
perm_mask = CAP_PERM_MASK_RW;
|
||||
if (perm == 4)
|
||||
perm_mask = CAP_PERM_MASK_RX;
|
||||
value = __builtin_cheri_perms_and (value, perm_mask);
|
||||
|
||||
/* Seal capabilities, which provide execute permission, with MORELLO_RB. */
|
||||
if (perm == 4)
|
||||
value = __builtin_cheri_seal_entry (value);
|
||||
return value;
|
||||
}
|
||||
|
||||
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 *) main_map->l_addr + reloc->r_offset;
|
||||
uintptr_t *__attribute__((may_alias)) cap_reloc_addr = reloc_addr;
|
||||
uintptr_t value
|
||||
= morello_relative_value (main_map->l_addr, reloc, reloc_addr);
|
||||
*cap_reloc_addr = elf_ifunc_invoke (value);
|
||||
}
|
||||
else
|
||||
__libc_fatal ("Unexpected reloc type in static binary.\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,438 @@
|
||||
/* 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 (l, l_info[DT_PLTGOT]);
|
||||
if (got[1])
|
||||
{
|
||||
l->l_mach.plt = (uint64_t) got[1] + l->l_addr;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/* Load address of the dynamic linker with correct bounds. */
|
||||
static uintptr_t __attribute__ ((unused))
|
||||
elf_machine_load_address_from_args (void *arg)
|
||||
{
|
||||
uintptr_t *sp;
|
||||
long argc;
|
||||
uintptr_t phdr = 0;
|
||||
size_t phentsize = sizeof (ElfW(Phdr));
|
||||
size_t phnum = 0;
|
||||
|
||||
sp = arg;
|
||||
argc = sp[0];
|
||||
/* Skip argv. */
|
||||
sp += argc + 2;
|
||||
/* Skip environ. */
|
||||
for (; *sp; sp++);
|
||||
sp++;
|
||||
for (; *sp != AT_NULL; sp += 2)
|
||||
{
|
||||
long t = sp[0];
|
||||
if (t == AT_BASE && sp[1])
|
||||
return sp[1];
|
||||
else if (t == AT_PHDR)
|
||||
phdr = sp[1];
|
||||
else if (t == AT_PHNUM)
|
||||
phnum = sp[1];
|
||||
else if (t == AT_PHENT)
|
||||
phentsize = sp[1];
|
||||
}
|
||||
for (size_t i = 0; i < phnum; i++)
|
||||
{
|
||||
ElfW(Phdr) *p = (ElfW(Phdr) *)(phdr + i * phentsize);
|
||||
if (p->p_type == PT_PHDR)
|
||||
return phdr - p->p_vaddr;
|
||||
if (p->p_type == PT_DYNAMIC)
|
||||
return (uintptr_t) elf_machine_runtime_dynamic () - p->p_vaddr;
|
||||
}
|
||||
/* Fail. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
|
||||
/* Return the address of the entry point. */
|
||||
#define ELF_MACHINE_START_ADDRESS(map, start) ((map)->l_addr + ((start) - (ElfW(Addr))(map)->l_addr))
|
||||
|
||||
#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_value (map->l_addr, 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
|
||||
{
|
||||
# ifndef RTLD_BOOTSTRAP
|
||||
const ElfW(Sym) *const refsym = sym;
|
||||
# endif
|
||||
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;
|
||||
switch (ELFW(ST_TYPE) (sym->st_info))
|
||||
{
|
||||
case STT_OBJECT:
|
||||
value = __builtin_cheri_bounds_set_exact (value, sym->st_size);
|
||||
perm_mask = CAP_PERM_MASK_RW;
|
||||
break;
|
||||
case STT_FUNC:
|
||||
case STT_GNU_IFUNC:
|
||||
/* Use l_addr for function pointer bounds. */
|
||||
value = sym_map->l_addr + (value - sym_map->l_addr);
|
||||
perm_mask = CAP_PERM_MASK_RX;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
const char *strtab;
|
||||
strtab = (const void *) D_PTR (sym_map, l_info[DT_STRTAB]);
|
||||
_dl_error_printf ("%s: symbol `%s' from `%s' has unknown type, when relocating `%s'.\n",
|
||||
RTLD_PROGNAME, strtab + sym->st_name, sym_map->l_name, map->l_name);
|
||||
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_value (map->l_addr, 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 (uintptr_t l_addr,
|
||||
const ElfW(Rela) *reloc,
|
||||
void *const reloc_addr)
|
||||
{
|
||||
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_value (l_addr, 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[],
|
||||
uintptr_t l_addr,
|
||||
const ElfW(Rela) *reloc,
|
||||
int skip_ifunc)
|
||||
{
|
||||
void *reloc_addr = (void *) (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);
|
||||
/* 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 = (uint64_t) *cap_reloc_addr + l_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_value (map->l_addr, 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,25 @@
|
||||
/* Check if dynamic section should be relocated. 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/>. */
|
||||
|
||||
#ifndef _DL_RELOCATE_LD_H
|
||||
#define _DL_RELOCATE_LD_H
|
||||
|
||||
/* Don't relocate the dynamic section because capabilities don't fit. */
|
||||
#define DL_RO_DYN_SECTION 1
|
||||
|
||||
#endif /* _DL_RELOCATE_LD_H */
|
||||
@@ -0,0 +1,68 @@
|
||||
/* ld.so _start code.
|
||||
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>
|
||||
|
||||
ENTRY(_start)
|
||||
|
||||
/* Create an initial frame with 0 LR and FP */
|
||||
cfi_undefined (c30)
|
||||
mov c29, czr
|
||||
mov c30, czr
|
||||
mov c0, csp
|
||||
bl _dl_start
|
||||
/* Returns user entry point in x0. */
|
||||
mov c21, c0
|
||||
.globl _dl_start_user
|
||||
.type _dl_start_user, %function
|
||||
_dl_start_user:
|
||||
/* Get argc. */
|
||||
ldr x1, [csp]
|
||||
/* Get argv. */
|
||||
add c2, csp, 16
|
||||
/* Compute envp. */
|
||||
add c3, c2, x1, lsl 4
|
||||
add c3, c3, 16
|
||||
|
||||
adrp c16, capinit_rtld_local
|
||||
ldr c16, [c16, :lo12:capinit_rtld_local]
|
||||
ldr c0, [c16]
|
||||
bl _dl_init
|
||||
/* Load the finalizer function. */
|
||||
adrp c0, capinit_dl_fini
|
||||
ldr c0, [c0, :lo12:capinit_dl_fini]
|
||||
/* Jump to the user's entry point. */
|
||||
mov c16, c21
|
||||
br c16
|
||||
END(_start)
|
||||
|
||||
.section .data.rel.ro.local,"aw"
|
||||
.align 4
|
||||
.type capinit_rtld_local, %object
|
||||
.size capinit_rtld_local, 16
|
||||
capinit_rtld_local:
|
||||
.capinit _rtld_local
|
||||
.xword 0
|
||||
.xword 0
|
||||
.type capinit_dl_fini, %object
|
||||
.size capinit_dl_fini, 16
|
||||
capinit_dl_fini:
|
||||
.capinit _dl_fini
|
||||
.xword 0
|
||||
.xword 0
|
||||
@@ -0,0 +1,229 @@
|
||||
/* Thread-local storage handling in the ELF dynamic linker.
|
||||
AArch64 Morello version.
|
||||
Copyright (C) 2011-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 <tls.h>
|
||||
#include "tlsdesc.h"
|
||||
|
||||
#define NSAVEDQREGPAIRS 16
|
||||
#define SAVE_Q_REGISTERS \
|
||||
stp q0, q1, [csp, #-32*NSAVEDQREGPAIRS]!; \
|
||||
cfi_adjust_cfa_offset (32*NSAVEDQREGPAIRS); \
|
||||
stp q2, q3, [csp, #32*1]; \
|
||||
stp q4, q5, [csp, #32*2]; \
|
||||
stp q6, q7, [csp, #32*3]; \
|
||||
stp q8, q9, [csp, #32*4]; \
|
||||
stp q10, q11, [csp, #32*5]; \
|
||||
stp q12, q13, [csp, #32*6]; \
|
||||
stp q14, q15, [csp, #32*7]; \
|
||||
stp q16, q17, [csp, #32*8]; \
|
||||
stp q18, q19, [csp, #32*9]; \
|
||||
stp q20, q21, [csp, #32*10]; \
|
||||
stp q22, q23, [csp, #32*11]; \
|
||||
stp q24, q25, [csp, #32*12]; \
|
||||
stp q26, q27, [csp, #32*13]; \
|
||||
stp q28, q29, [csp, #32*14]; \
|
||||
stp q30, q31, [csp, #32*15];
|
||||
|
||||
#define RESTORE_Q_REGISTERS \
|
||||
ldp q2, q3, [csp, #32*1]; \
|
||||
ldp q4, q5, [csp, #32*2]; \
|
||||
ldp q6, q7, [csp, #32*3]; \
|
||||
ldp q8, q9, [csp, #32*4]; \
|
||||
ldp q10, q11, [csp, #32*5]; \
|
||||
ldp q12, q13, [csp, #32*6]; \
|
||||
ldp q14, q15, [csp, #32*7]; \
|
||||
ldp q16, q17, [csp, #32*8]; \
|
||||
ldp q18, q19, [csp, #32*9]; \
|
||||
ldp q20, q21, [csp, #32*10]; \
|
||||
ldp q22, q23, [csp, #32*11]; \
|
||||
ldp q24, q25, [csp, #32*12]; \
|
||||
ldp q26, q27, [csp, #32*13]; \
|
||||
ldp q28, q29, [csp, #32*14]; \
|
||||
ldp q30, q31, [csp, #32*15]; \
|
||||
ldp q0, q1, [csp], #32*NSAVEDQREGPAIRS; \
|
||||
cfi_adjust_cfa_offset (-32*NSAVEDQREGPAIRS);
|
||||
|
||||
.text
|
||||
|
||||
/* Compute the address for symbols in the static TLS block.
|
||||
Prototype:
|
||||
_dl_tlsdesc_return (tlsdesc *tdp, void *unused, void *tp);
|
||||
*/
|
||||
.hidden _dl_tlsdesc_return
|
||||
.global _dl_tlsdesc_return
|
||||
.type _dl_tlsdesc_return,%function
|
||||
cfi_startproc
|
||||
.align 2
|
||||
_dl_tlsdesc_return:
|
||||
ldp x0, x1, [c0, #PTR_SIZE] /* Load offset, size. */
|
||||
add c0, c2, x0
|
||||
scbndse c0, c0, x1
|
||||
RET
|
||||
cfi_endproc
|
||||
.size _dl_tlsdesc_return, .-_dl_tlsdesc_return
|
||||
|
||||
/* Handler for undefined weak TLS symbols: returns NULL.
|
||||
Prototype:
|
||||
_dl_tlsdesc_undefweak (tlsdesc *tdp, void *unused, void *tp);
|
||||
*/
|
||||
.hidden _dl_tlsdesc_undefweak
|
||||
.global _dl_tlsdesc_undefweak
|
||||
.type _dl_tlsdesc_undefweak,%function
|
||||
cfi_startproc
|
||||
.align 2
|
||||
_dl_tlsdesc_undefweak:
|
||||
mov x0, 0
|
||||
RET
|
||||
cfi_endproc
|
||||
.size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak
|
||||
|
||||
#ifdef SHARED
|
||||
/* Handler for dynamic TLS symbols.
|
||||
Prototype:
|
||||
_dl_tlsdesc_dynamic (tlsdesc *tdp, void *unused, void *tp);
|
||||
|
||||
The second word of the descriptor points to a
|
||||
tlsdesc_dynamic_arg structure.
|
||||
|
||||
Returns the address of the tls object.
|
||||
|
||||
void *
|
||||
_dl_tlsdesc_dynamic (struct tlsdesc *tdp, void *unused, void *tp)
|
||||
{
|
||||
struct tlsdesc_dynamic_arg *td = tdp->arg;
|
||||
dtv_t *dtv = *(dtv_t **)((char *)tp + TCBHEAD_DTV);
|
||||
if (__builtin_expect (td->gen_count <= dtv[0].counter
|
||||
&& (dtv[td->tlsinfo.ti_module].pointer.val
|
||||
!= TLS_DTV_UNALLOCATED),
|
||||
1))
|
||||
return dtv[td->tlsinfo.ti_module].pointer.val
|
||||
+ td->tlsinfo.ti_offset;
|
||||
|
||||
return ___tls_get_addr (&td->tlsinfo);
|
||||
}
|
||||
*/
|
||||
.hidden _dl_tlsdesc_dynamic
|
||||
.global _dl_tlsdesc_dynamic
|
||||
.type _dl_tlsdesc_dynamic,%function
|
||||
cfi_startproc
|
||||
.align 2
|
||||
_dl_tlsdesc_dynamic:
|
||||
|
||||
/* Save just enough registers to support fast path, if we fall
|
||||
into slow path we will save additional registers. */
|
||||
stp c3, c4, [csp, #-32]!
|
||||
cfi_adjust_cfa_offset (32)
|
||||
cfi_rel_offset (c3, 0)
|
||||
cfi_rel_offset (c4, 16)
|
||||
|
||||
ldr c1, [c0,#TLSDESC_ARG]
|
||||
ldr c0, [c2,#TCBHEAD_DTV]
|
||||
ldr x3, [c1,#TLSDESC_GEN_COUNT]
|
||||
ldr x4, [c0,#DTV_COUNTER]
|
||||
cmp x3, x4
|
||||
b.hi 2f
|
||||
/* Load r3 = td->tlsinfo.ti_module and r4 = td->tlsinfo.ti_offset. */
|
||||
ldp x3, x4, [c1,#TLSDESC_MODID]
|
||||
lsl x3, x3, #(PTR_LOG_SIZE+1)
|
||||
ldr c0, [c0, x3] /* Load val member of DTV entry. */
|
||||
cmp x0, #TLS_DTV_UNALLOCATED
|
||||
b.eq 2f
|
||||
cfi_remember_state
|
||||
/* Load r3 = td->tlsinfo.ti_size. */
|
||||
ldr x3, [c1, #TLSDESC_SIZE]
|
||||
add c0, c0, x4
|
||||
scbndse c0, c0, x3
|
||||
1:
|
||||
ldp c3, c4, [csp], #32
|
||||
cfi_adjust_cfa_offset (-32)
|
||||
RET
|
||||
2:
|
||||
/* This is the slow path. We need to call __tls_get_addr() which
|
||||
means we need to save and restore all the register that the
|
||||
callee will trash. */
|
||||
|
||||
/* Save the remaining registers that we must treat as caller save. */
|
||||
cfi_restore_state
|
||||
|
||||
# define NSAVEXREGPAIRS 9
|
||||
stp c29, c30, [csp,#-32*NSAVEXREGPAIRS]!
|
||||
cfi_adjust_cfa_offset (32*NSAVEXREGPAIRS)
|
||||
cfi_rel_offset (c29, 0)
|
||||
cfi_rel_offset (c30, 16)
|
||||
mov c29, csp
|
||||
stp c5, c6, [csp, #32*1]
|
||||
stp c7, c8, [csp, #32*2]
|
||||
stp c9, c10, [csp, #32*3]
|
||||
stp c11, c12, [csp, #32*4]
|
||||
stp c13, c14, [csp, #32*5]
|
||||
stp c15, c16, [csp, #32*6]
|
||||
stp c17, c18, [csp, #32*7]
|
||||
cfi_rel_offset (c5, 32*1)
|
||||
cfi_rel_offset (c6, 32*1+8)
|
||||
cfi_rel_offset (c7, 32*2)
|
||||
cfi_rel_offset (c8, 32*2+8)
|
||||
cfi_rel_offset (c9, 32*3)
|
||||
cfi_rel_offset (c10, 32*3+8)
|
||||
cfi_rel_offset (c11, 32*4)
|
||||
cfi_rel_offset (c12, 32*4+8)
|
||||
cfi_rel_offset (c13, 32*5)
|
||||
cfi_rel_offset (c14, 32*5+8)
|
||||
cfi_rel_offset (c15, 32*6)
|
||||
cfi_rel_offset (c16, 32*6+8)
|
||||
cfi_rel_offset (c17, 32*7)
|
||||
cfi_rel_offset (c18, 32*7+8)
|
||||
|
||||
SAVE_Q_REGISTERS
|
||||
|
||||
/* TODO: remove once __tls_get_addr is fixed. */
|
||||
str c1, [csp, #32*8]
|
||||
|
||||
mov c0, c1
|
||||
bl __tls_get_addr
|
||||
|
||||
/* TODO: __tls_get_addr should return bounded pointer,
|
||||
currently it does not so bound it here. */
|
||||
ldr c1, [csp, #32*8]
|
||||
ldr x3, [c1, #TLSDESC_SIZE]
|
||||
scbndse c0, c0, x3
|
||||
|
||||
mrs c2, ctpidr_el0 /* Restore c2. */
|
||||
|
||||
RESTORE_Q_REGISTERS
|
||||
|
||||
ldp c5, c6, [csp, #32*1]
|
||||
ldp c7, c8, [csp, #32*2]
|
||||
ldp c9, c10, [csp, #32*3]
|
||||
ldp c11, c12, [csp, #32*4]
|
||||
ldp c13, c14, [csp, #32*5]
|
||||
ldp c15, c16, [csp, #32*6]
|
||||
ldp c17, c18, [csp, #32*7]
|
||||
|
||||
ldp c29, c30, [csp], #32*NSAVEXREGPAIRS
|
||||
cfi_adjust_cfa_offset (-32*NSAVEXREGPAIRS)
|
||||
cfi_restore (c29)
|
||||
cfi_restore (c30)
|
||||
|
||||
b 1b
|
||||
cfi_endproc
|
||||
.size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic
|
||||
# undef NSAVEXREGPAIRS
|
||||
#endif
|
||||
@@ -0,0 +1,62 @@
|
||||
/* Thread-local storage descriptor handling in the ELF dynamic linker.
|
||||
Morello version.
|
||||
Copyright (C) 2011-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_DL_TLSDESC_H
|
||||
#define _AARCH64_MORELLO_DL_TLSDESC_H 1
|
||||
|
||||
/* Type used to represent a TLS descriptor in the GOT. */
|
||||
struct tlsdesc
|
||||
{
|
||||
void *(*entry) (struct tlsdesc *, void *, void *);
|
||||
union {
|
||||
void *arg;
|
||||
struct { unsigned long off, size; } pair;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct dl_tls_index
|
||||
{
|
||||
unsigned long int ti_module;
|
||||
unsigned long int ti_offset;
|
||||
unsigned long int ti_size;
|
||||
} tls_index;
|
||||
|
||||
/* Type used as the argument in a TLS descriptor for a symbol that
|
||||
needs dynamic TLS offsets. */
|
||||
struct tlsdesc_dynamic_arg
|
||||
{
|
||||
tls_index tlsinfo;
|
||||
size_t gen_count;
|
||||
};
|
||||
|
||||
extern attribute_hidden void *
|
||||
_dl_tlsdesc_return (struct tlsdesc *, void *, void *);
|
||||
|
||||
extern attribute_hidden void *
|
||||
_dl_tlsdesc_undefweak (struct tlsdesc *, void *, void *);
|
||||
|
||||
# ifdef SHARED
|
||||
extern void *_dl_make_tlsdesc_dynamic (struct link_map *, size_t);
|
||||
|
||||
extern attribute_hidden void *
|
||||
_dl_tlsdesc_dynamic (struct tlsdesc *, void *, void *);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,307 @@
|
||||
/* Copyright (C) 2005-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 <libc-symbols.h>
|
||||
|
||||
#include "dl-link.h"
|
||||
|
||||
#define ip0 c16
|
||||
#define ip0l c16
|
||||
#define ip1 c17
|
||||
#define lr c30
|
||||
|
||||
#define RELA_SIZE 24
|
||||
|
||||
.text
|
||||
.globl _dl_runtime_resolve
|
||||
.type _dl_runtime_resolve, #function
|
||||
cfi_startproc
|
||||
.align 2
|
||||
_dl_runtime_resolve:
|
||||
/* Morello we get called with:
|
||||
ip0 &PLTGOT[2]
|
||||
ip1 temp(dl resolver entry point)
|
||||
[sp, #16] lr
|
||||
[sp, #0] &PLTGOT[n]
|
||||
*/
|
||||
|
||||
cfi_rel_offset (lr, 16)
|
||||
|
||||
/* Save arguments. */
|
||||
stp c8, c9, [csp, #-(160+8*16)]!
|
||||
cfi_adjust_cfa_offset (160+8*16)
|
||||
cfi_rel_offset (c8, 0)
|
||||
cfi_rel_offset (c9, 16)
|
||||
|
||||
stp c6, c7, [csp, #32]
|
||||
cfi_rel_offset (c6, 32)
|
||||
cfi_rel_offset (c7, 48)
|
||||
|
||||
stp c4, c5, [csp, #64]
|
||||
cfi_rel_offset (c4, 64)
|
||||
cfi_rel_offset (c5, 80)
|
||||
|
||||
stp c2, c3, [csp, #96]
|
||||
cfi_rel_offset (c2, 96)
|
||||
cfi_rel_offset (c3, 112)
|
||||
|
||||
stp c0, c1, [csp, #128]
|
||||
cfi_rel_offset (c0, 128)
|
||||
cfi_rel_offset (c1, 144)
|
||||
|
||||
stp q0, q1, [csp, #(160+0*16)]
|
||||
cfi_rel_offset (q0, 160+0*16)
|
||||
cfi_rel_offset (q1, 160+1*16)
|
||||
|
||||
stp q2, q3, [csp, #(160+2*16)]
|
||||
cfi_rel_offset (q0, 160+2*16)
|
||||
cfi_rel_offset (q1, 160+3*16)
|
||||
|
||||
stp q4, q5, [csp, #(160+4*16)]
|
||||
cfi_rel_offset (q0, 160+4*16)
|
||||
cfi_rel_offset (q1, 160+5*16)
|
||||
|
||||
stp q6, q7, [csp, #(160+6*16)]
|
||||
cfi_rel_offset (q0, 160+6*16)
|
||||
cfi_rel_offset (q1, 160+7*16)
|
||||
|
||||
/* Get pointer to linker struct. */
|
||||
ldr c0, [ip0, #-PTR_SIZE]
|
||||
|
||||
/* Prepare to call _dl_fixup(). */
|
||||
ldr c1, [csp, 160+8*16] /* Recover &PLTGOT[n] */
|
||||
|
||||
sub x1, x1, x16
|
||||
add x1, x1, x1, lsl #1
|
||||
lsr x1, x1, #1
|
||||
sub x1, x1, #RELA_SIZE
|
||||
|
||||
/* Call fixup routine. */
|
||||
bl _dl_fixup
|
||||
|
||||
/* Save the return. */
|
||||
mov ip0, c0
|
||||
|
||||
/* Get arguments and return address back. */
|
||||
ldp q0, q1, [csp, #(160+0*16)]
|
||||
ldp q2, q3, [csp, #(160+2*16)]
|
||||
ldp q4, q5, [csp, #(160+4*16)]
|
||||
ldp q6, q7, [csp, #(160+6*16)]
|
||||
ldp c0, c1, [csp, #128]
|
||||
ldp c2, c3, [csp, #96]
|
||||
ldp c4, c5, [csp, #64]
|
||||
ldp c6, c7, [csp, #32]
|
||||
ldp c8, c9, [csp], #(160+8*16)
|
||||
cfi_adjust_cfa_offset (-(160+8*16))
|
||||
|
||||
ldp ip1, lr, [csp], #32
|
||||
cfi_adjust_cfa_offset (-32)
|
||||
|
||||
/* Jump to the newly found address. */
|
||||
br ip0
|
||||
|
||||
cfi_endproc
|
||||
.size _dl_runtime_resolve, .-_dl_runtime_resolve
|
||||
#ifndef PROF
|
||||
.globl _dl_runtime_profile
|
||||
.type _dl_runtime_profile, #function
|
||||
cfi_startproc
|
||||
.align 2
|
||||
_dl_runtime_profile:
|
||||
|
||||
/* Morello we get called with:
|
||||
ip0 &PLTGOT[2]
|
||||
ip1 temp(dl resolver entry point)
|
||||
[csp, #16] lr
|
||||
[csp, #0] &PLTGOT[n]
|
||||
|
||||
Stack frame layout:
|
||||
[csp, #...] lr
|
||||
[csp, #...] &PLTGOT[n]
|
||||
[csp, #192] La_aarch64_regs
|
||||
[csp, #96] La_aarch64_retval
|
||||
[csp, #80] frame size return from pltenter
|
||||
[csp, #64] dl_profile_call saved c1
|
||||
[csp, #48] dl_profile_call saved c0
|
||||
[csp, #32] t1
|
||||
[csp, #0] c29, lr <- c29
|
||||
*/
|
||||
|
||||
# define OFFSET_T1 32
|
||||
# define OFFSET_SAVED_CALL_X0 OFFSET_T1 + 16
|
||||
# define OFFSET_FS OFFSET_SAVED_CALL_X0 + 32
|
||||
# define OFFSET_RV OFFSET_FS + 16
|
||||
# define OFFSET_RG OFFSET_RV + DL_SIZEOF_RV
|
||||
|
||||
# define SF_SIZE OFFSET_RG + DL_SIZEOF_RG
|
||||
|
||||
# define OFFSET_PLTGOTN SF_SIZE
|
||||
# define OFFSET_LR OFFSET_PLTGOTN + 16
|
||||
|
||||
/* Save arguments. */
|
||||
mov c11, csp
|
||||
sub x11, x11, #SF_SIZE
|
||||
scvalue csp, csp, x11
|
||||
cfi_adjust_cfa_offset (SF_SIZE)
|
||||
stp c29, c30, [csp, #0]
|
||||
mov c29, csp
|
||||
cfi_def_cfa_register (c29)
|
||||
cfi_rel_offset (c29, 0)
|
||||
cfi_rel_offset (lr, 8)
|
||||
|
||||
stp c0, c1, [c29, #OFFSET_RG + DL_OFFSET_RG_X0 + 32*0]
|
||||
cfi_rel_offset (c0, OFFSET_RG + DL_OFFSET_RG_X0 + 32*0 + 0)
|
||||
cfi_rel_offset (c1, OFFSET_RG + DL_OFFSET_RG_X0 + 32*0 + 16)
|
||||
stp c2, c3, [c29, #OFFSET_RG + DL_OFFSET_RG_X0 + 32*1]
|
||||
cfi_rel_offset (c2, OFFSET_RG + DL_OFFSET_RG_X0 + 32*1 + 0)
|
||||
cfi_rel_offset (c3, OFFSET_RG + DL_OFFSET_RG_X0 + 32*1 + 16)
|
||||
stp c4, c5, [c29, #OFFSET_RG + DL_OFFSET_RG_X0 + 32*2]
|
||||
cfi_rel_offset (c4, OFFSET_RG + DL_OFFSET_RG_X0 + 32*2 + 0)
|
||||
cfi_rel_offset (c5, OFFSET_RG + DL_OFFSET_RG_X0 + 32*2 + 16)
|
||||
stp c6, c7, [c29, #OFFSET_RG + DL_OFFSET_RG_X0 + 32*3]
|
||||
cfi_rel_offset (c6, OFFSET_RG + DL_OFFSET_RG_X0 + 32*3 + 0)
|
||||
cfi_rel_offset (c7, OFFSET_RG + DL_OFFSET_RG_X0 + 32*3 + 16)
|
||||
|
||||
stp q0, q1, [c29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*0]
|
||||
cfi_rel_offset (q0, OFFSET_RG + DL_OFFSET_RG_V0 + 32*0)
|
||||
cfi_rel_offset (q1, OFFSET_RG + DL_OFFSET_RG_V0 + 32*0 + 16)
|
||||
stp q2, q3, [c29, #OFFSET_RG+ DL_OFFSET_RG_V0 + 32*1]
|
||||
cfi_rel_offset (q2, OFFSET_RG + DL_OFFSET_RG_V0 + 32*1 + 0)
|
||||
cfi_rel_offset (q3, OFFSET_RG + DL_OFFSET_RG_V0 + 32*1 + 16)
|
||||
stp q4, q5, [c29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*2]
|
||||
cfi_rel_offset (q4, OFFSET_RG + DL_OFFSET_RG_V0 + 32*2 + 0)
|
||||
cfi_rel_offset (q5, OFFSET_RG + DL_OFFSET_RG_V0 + 32*2 + 16)
|
||||
stp q6, q7, [c29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*3]
|
||||
cfi_rel_offset (q6, OFFSET_RG + DL_OFFSET_RG_V0 + 32*3 + 0)
|
||||
cfi_rel_offset (q7, OFFSET_RG + DL_OFFSET_RG_V0 + 32*3 + 16)
|
||||
|
||||
add c0, c29, #SF_SIZE + 32
|
||||
ldr c1, [c29, #OFFSET_LR]
|
||||
stp c0, c1, [c29, #OFFSET_RG + DL_OFFSET_RG_SP]
|
||||
|
||||
/* Get pointer to linker struct. */
|
||||
ldr c0, [ip0, #-PTR_SIZE]
|
||||
|
||||
/* Prepare to call _dl_profile_fixup(). */
|
||||
ldr c1, [c29, OFFSET_PLTGOTN] /* Recover &PLTGOT[n] */
|
||||
|
||||
mov c11, c1
|
||||
sub x1, x1, x16
|
||||
add x1, x1, x1, lsl #1
|
||||
lsl x1, x1, #3
|
||||
sub x1, x1, #(RELA_SIZE<<3)
|
||||
lsr x1, x1, #3
|
||||
scvalue c1, c11, x1
|
||||
|
||||
stp c0, c1, [c29, #OFFSET_SAVED_CALL_X0]
|
||||
|
||||
/* Set up extra args for _dl_profile_fixup */
|
||||
ldr c2, [c29, #OFFSET_LR] /* load saved LR */
|
||||
add c3, c29, #OFFSET_RG /* address of La_aarch64_reg */
|
||||
add c4, c29, #OFFSET_FS /* address of framesize */
|
||||
bl _dl_profile_fixup
|
||||
|
||||
ldr ip0l, [c29, #OFFSET_FS] /* framesize == 0 */
|
||||
cmp x16, #0
|
||||
bge 1f
|
||||
cfi_remember_state
|
||||
|
||||
/* Save the return. */
|
||||
mov ip0, c0
|
||||
|
||||
/* Get arguments and return address back. */
|
||||
ldp c0, c1, [c29, #OFFSET_RG + DL_OFFSET_RG_X0 + 32*0]
|
||||
ldp c2, c3, [c29, #OFFSET_RG + DL_OFFSET_RG_X0 + 32*1]
|
||||
ldp c4, c5, [c29, #OFFSET_RG + DL_OFFSET_RG_X0 + 32*2]
|
||||
ldp c6, c7, [c29, #OFFSET_RG + DL_OFFSET_RG_X0 + 32*3]
|
||||
ldp q0, q1, [c29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*0]
|
||||
ldp q2, q3, [c29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*1]
|
||||
ldp q4, q5, [c29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*2]
|
||||
ldp q6, q7, [c29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*3]
|
||||
|
||||
cfi_def_cfa_register (csp)
|
||||
ldp c29, c30, [c29, #0]
|
||||
cfi_restore(c29)
|
||||
cfi_restore(c30)
|
||||
|
||||
add csp, csp, SF_SIZE + 16
|
||||
cfi_adjust_cfa_offset (- SF_SIZE - 32)
|
||||
|
||||
/* Jump to the newly found address. */
|
||||
br ip0
|
||||
|
||||
cfi_restore_state
|
||||
1:
|
||||
/* The new frame size is in ip0. */
|
||||
|
||||
mov c11, c1
|
||||
sub x1, x29, x16
|
||||
and x12, x1, #0xfffffffffffffff0
|
||||
scvalue csp, csp, x12
|
||||
scvalue c1, c11, x1
|
||||
|
||||
str c0, [c29, #OFFSET_T1]
|
||||
|
||||
mov c0, csp
|
||||
add c1, c29, #SF_SIZE + 16
|
||||
mov c2, ip0
|
||||
bl memcpy
|
||||
|
||||
ldr ip0, [c29, #OFFSET_T1]
|
||||
|
||||
/* Call the function. */
|
||||
ldp c0, c1, [c29, #OFFSET_RG + DL_OFFSET_RG_X0 + 32*0]
|
||||
ldp c2, c3, [c29, #OFFSET_RG + DL_OFFSET_RG_X0 + 32*1]
|
||||
ldp c4, c5, [c29, #OFFSET_RG + DL_OFFSET_RG_X0 + 32*2]
|
||||
ldp c6, c7, [c29, #OFFSET_RG + DL_OFFSET_RG_X0 + 32*3]
|
||||
ldp q0, q1, [c29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*0]
|
||||
ldp q2, q3, [c29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*1]
|
||||
ldp q4, q5, [c29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*2]
|
||||
ldp q6, q7, [c29, #OFFSET_RG + DL_OFFSET_RG_V0 + 32*3]
|
||||
blr ip0
|
||||
stp c0, c1, [c29, #OFFSET_RV + DL_OFFSET_RV_X0]
|
||||
stp q0, q1, [c29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0]
|
||||
stp q2, q3, [c29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1]
|
||||
|
||||
/* Setup call to pltexit */
|
||||
ldp c0, c1, [c29, #OFFSET_SAVED_CALL_X0]
|
||||
add c2, c29, #OFFSET_RG
|
||||
add c3, c29, #OFFSET_RV
|
||||
bl _dl_audit_pltexit
|
||||
|
||||
ldp c0, c1, [c29, #OFFSET_RV + DL_OFFSET_RV_X0]
|
||||
ldp d0, d1, [c29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0]
|
||||
ldp d2, d3, [c29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1]
|
||||
/* LR from within La_aarch64_reg */
|
||||
ldr lr, [c29, #OFFSET_RG + DL_OFFSET_RG_LR]
|
||||
cfi_restore(lr)
|
||||
|
||||
mov csp, c29
|
||||
cfi_def_cfa_register (csp)
|
||||
ldr c29, [c29, #0]
|
||||
cfi_restore(c29)
|
||||
add csp, csp, SF_SIZE + 32
|
||||
cfi_adjust_cfa_offset (- SF_SIZE - 32)
|
||||
|
||||
br lr
|
||||
|
||||
cfi_endproc
|
||||
.size _dl_runtime_profile, .-_dl_runtime_profile
|
||||
#endif
|
||||
.previous
|
||||
@@ -0,0 +1,33 @@
|
||||
/* Simple memchr.
|
||||
|
||||
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; see the file COPYING.LIB. If
|
||||
not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void *__memchr (const void *s, int c, size_t n)
|
||||
{
|
||||
unsigned char uc = c;
|
||||
const unsigned char *us = s;
|
||||
for (; n > 0; n--, us++)
|
||||
if (*us == uc)
|
||||
return (void *) us;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
weak_alias (__memchr, memchr)
|
||||
libc_hidden_builtin_def (memchr)
|
||||
@@ -0,0 +1,38 @@
|
||||
/* Simple memcmp.
|
||||
|
||||
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; see the file COPYING.LIB. If
|
||||
not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
int memcmp (const void *s1, const void *s2, size_t n)
|
||||
{
|
||||
const unsigned char *us1 = s1;
|
||||
const unsigned char *us2 = s2;
|
||||
for (; n > 0; us1++, us2++, n--)
|
||||
if (*us1 != *us2)
|
||||
return *us1 - *us2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef bcmp
|
||||
weak_alias (memcmp, bcmp)
|
||||
libc_hidden_builtin_def (memcmp)
|
||||
|
||||
#undef __memcmpeq
|
||||
strong_alias (memcmp, __memcmpeq)
|
||||
libc_hidden_def(__memcmpeq)
|
||||
@@ -0,0 +1,486 @@
|
||||
/* 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>
|
||||
|
||||
/* Assumptions:
|
||||
*
|
||||
* ARMv8-a, AArch64, Morello, Advanced SIMD, unaligned accesses.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MEMMOVE
|
||||
# define MEMMOVE memmove
|
||||
#endif
|
||||
#ifndef MEMCPY
|
||||
# define MEMCPY memcpy
|
||||
#endif
|
||||
|
||||
#define xdstin x0
|
||||
#define xsrc x1
|
||||
#define count x2
|
||||
#define xsrcend x4
|
||||
#define A_l x6
|
||||
#define A_lw w6
|
||||
#define A_h x7
|
||||
#define B_l x8
|
||||
#define B_lw w8
|
||||
#define B_h x9
|
||||
#define C_lw w10
|
||||
#define auoff x14
|
||||
#define cap_count x15
|
||||
#define tmp1 x16
|
||||
#define tmp2 x17
|
||||
|
||||
#if defined(__CHERI_PURE_CAPABILITY__)
|
||||
#define dstin c0
|
||||
#define src c1
|
||||
#define dst c3
|
||||
#define srcend c4
|
||||
#define dstend c5
|
||||
#define tmp1_ptr c16
|
||||
#else
|
||||
#define dstin x0
|
||||
#define src x1
|
||||
#define dst x3
|
||||
#define srcend x4
|
||||
#define dstend x5
|
||||
#define tmp1_ptr x16
|
||||
#endif
|
||||
|
||||
#define A_q q0
|
||||
#define B_q q1
|
||||
#define C_q q2
|
||||
#define D_q q3
|
||||
#define E_q q4
|
||||
#define F_q q5
|
||||
#define G_q q6
|
||||
#define H_q q7
|
||||
|
||||
#define A_cap c6
|
||||
#define B_cap c7
|
||||
#define C_cap c8
|
||||
#define D_cap c9
|
||||
#define E_cap c10
|
||||
#define F_cap c11
|
||||
#define G_cap c12
|
||||
#define H_cap c13
|
||||
|
||||
|
||||
/* This algorithm has not been benchmarked. It's derived
|
||||
from the base aarch64 one with small changes to account
|
||||
for copying tags.
|
||||
|
||||
1. We're copying less than 16 bytes, so no capabilities.
|
||||
Use the traditional code path for these.
|
||||
2. src mod 16 != dst mode 16. We're not copying capabilities,
|
||||
so again use the traditional memcpy.
|
||||
3. We're copying more than 8 capabilities plus the head and tail.
|
||||
a. No overlap, use forward copy
|
||||
b. Overlap, use backward copy
|
||||
4. We're copying 0..8 capabilities
|
||||
a. No capabilities to copy. This means we are copying 16..30 bytes.
|
||||
Use the existing code path to do this from the original algorithm.
|
||||
b. Copying 1..2 capabilities plus the head and tail
|
||||
Use a branchless sequence.
|
||||
c. Copying 3..4 capabilities plus the head and tail
|
||||
Use a branchless sequence.
|
||||
d. Copying 5..8 capabilities plus the head and tail
|
||||
Use a branchless sequence.
|
||||
*/
|
||||
|
||||
ENTRY (MEMCPY)
|
||||
PTR_ARG (0)
|
||||
PTR_ARG (1)
|
||||
SIZE_ARG (2)
|
||||
add srcend, src, count
|
||||
add dstend, dstin, count
|
||||
|
||||
/* Copies of less than 16 bytes don't use capabilities. */
|
||||
cmp count, 16
|
||||
b.lo L(copy16)
|
||||
|
||||
/* If src mod 16 != dst mod 16 we're not transfering tags. */
|
||||
and tmp1, xsrc, 15
|
||||
and tmp2, xdstin, 15
|
||||
cmp tmp1, tmp2
|
||||
b.ne L(memcpy_nocap)
|
||||
|
||||
/* Get the number of capabilities that we need to store. */
|
||||
neg tmp2, tmp1
|
||||
add tmp2, tmp2, 16
|
||||
and auoff, tmp2, 15
|
||||
|
||||
sub cap_count, count, auoff
|
||||
lsr cap_count, cap_count, 4
|
||||
|
||||
cmp cap_count, 8
|
||||
b.hi L(copy_long_cap)
|
||||
cmp cap_count, 2
|
||||
b.hi L(copy32_128_cap)
|
||||
|
||||
/* Copy 0..2 capabilities using a branchless sequence. */
|
||||
cbz cap_count, L(copy32)
|
||||
ldr A_q, [src]
|
||||
ldr B_q, [srcend, -16]
|
||||
add src, src, auoff /* align up src to 16 bytes */
|
||||
#if defined(__CHERI_PURE_CAPABILITY__)
|
||||
alignd srcend, srcend, 4
|
||||
#else
|
||||
bic srcend, srcend, 15
|
||||
#endif
|
||||
ldr A_cap, [src]
|
||||
ldr B_cap, [srcend, -16]
|
||||
str A_q, [dstin]
|
||||
str B_q, [dstend, -16]
|
||||
add tmp1_ptr, dstin, auoff /* align up dstin to 16 bytes */
|
||||
#if defined (__CHERI_PURE_CAPABILITY__)
|
||||
alignd dstend, dstend, 4
|
||||
#else
|
||||
bic dstend, dstend, 15
|
||||
#endif
|
||||
str A_cap, [tmp1_ptr]
|
||||
str B_cap, [dstend, -16]
|
||||
ret
|
||||
|
||||
.p2align 4
|
||||
L(copy32_128_cap):
|
||||
cmp cap_count, 4
|
||||
b.hi L(copy128_cap)
|
||||
/* Copy 3..4 capabilties using a branchless sequence. */
|
||||
ldr A_q, [src]
|
||||
ldr B_q, [srcend, -16]
|
||||
add src, src, auoff /* align up src to 16 bytes */
|
||||
#if defined (__CHERI_PURE_CAPABILITY__)
|
||||
alignd srcend, srcend, 4
|
||||
#else
|
||||
bic srcend, srcend, 15
|
||||
#endif
|
||||
ldp A_cap, B_cap, [src]
|
||||
ldp C_cap, D_cap, [srcend, -32]
|
||||
str A_q, [dstin]
|
||||
str B_q, [dstend, -16]
|
||||
add tmp1_ptr, dstin, auoff /* align up dstin to 16 bytes */
|
||||
#if defined (__CHERI_PURE_CAPABILITY__)
|
||||
alignd dstend, dstend, 4
|
||||
#else
|
||||
bic dstend, dstend, 15
|
||||
#endif
|
||||
stp A_cap, B_cap, [tmp1_ptr]
|
||||
stp C_cap, D_cap, [dstend, -32]
|
||||
ret
|
||||
|
||||
.p2align 4
|
||||
L(copy128_cap):
|
||||
/* Copy 5..8 capabilities using a branchless sequence. */
|
||||
ldr A_q, [src]
|
||||
ldr B_q, [srcend, -16]
|
||||
add src, src, auoff /* align up src to 16 bytes */
|
||||
#if defined (__CHERI_PURE_CAPABILITY__)
|
||||
alignd srcend, srcend, 4
|
||||
#else
|
||||
bic srcend, srcend, 15
|
||||
#endif
|
||||
ldp A_cap, B_cap, [src]
|
||||
ldp C_cap, D_cap, [src, 32]
|
||||
ldp E_cap, F_cap, [srcend, -32]
|
||||
ldp G_cap, H_cap, [srcend, -64]
|
||||
str A_q, [dstin]
|
||||
str B_q, [dstend, -16]
|
||||
add tmp1_ptr, dstin, auoff /* align up src to 16 bytes */
|
||||
#if defined (__CHERI_PURE_CAPABILITY__)
|
||||
alignd dstend, dstend, 4
|
||||
#else
|
||||
bic dstend, dstend, 15
|
||||
#endif
|
||||
stp A_cap, B_cap, [tmp1_ptr]
|
||||
stp C_cap, D_cap, [tmp1_ptr, 32]
|
||||
stp E_cap, F_cap, [dstend, -32]
|
||||
stp G_cap, H_cap, [dstend, -64]
|
||||
ret
|
||||
|
||||
L(copy_long_cap):
|
||||
/* Use backwards copy if there is an overlap. */
|
||||
sub tmp1, xdstin, xsrc
|
||||
cmp tmp1, count
|
||||
b.lo L(copy_long_backwards_cap)
|
||||
|
||||
/* Copy 16 bytes and then align src to 16-byte alignment. */
|
||||
ldr D_q, [src]
|
||||
ldr E_cap, [src, auoff]
|
||||
and tmp1, xsrc, 15
|
||||
#if defined(__CHERI_PURE_CAPABILITY__)
|
||||
alignd src, src, 4
|
||||
neg tmp2, tmp1
|
||||
add dst, dstin, tmp2
|
||||
#else
|
||||
bic src, src, 15
|
||||
sub dst, dstin, tmp1
|
||||
#endif
|
||||
add count, count, tmp1 /* Count is now 16 too large. */
|
||||
ldp A_cap, B_cap, [src, 16]
|
||||
str D_q, [dstin]
|
||||
str E_cap, [dstin, auoff]
|
||||
ldp C_cap, D_cap, [src, 48]
|
||||
subs count, count, 128 + 16 /* Test and readjust count. */
|
||||
b.ls L(copy64_from_end_cap)
|
||||
L(loop64_cap):
|
||||
stp A_cap, B_cap, [dst, 16]
|
||||
ldp A_cap, B_cap, [src, 80]
|
||||
stp C_cap, D_cap, [dst, 48]
|
||||
ldp C_cap, D_cap, [src, 112]
|
||||
add src, src, 64
|
||||
add dst, dst, 64
|
||||
subs count, count, 64
|
||||
b.hi L(loop64_cap)
|
||||
|
||||
/* Write the last iteration and copy the last 16-byte aligned 64 byte block
|
||||
from the end and the tail. */
|
||||
L(copy64_from_end_cap):
|
||||
ldr A_q, [srcend, -16]
|
||||
#if defined(__CHERI_PURE_CAPABILITY__)
|
||||
alignd srcend, srcend, 4
|
||||
alignd tmp1_ptr, dstend, 4
|
||||
#else
|
||||
bic srcend, srcend, 15
|
||||
bic tmp1_ptr, dstend, 15
|
||||
#endif
|
||||
ldp E_cap, F_cap, [srcend, -64]
|
||||
stp A_cap, B_cap, [dst, 16]
|
||||
ldp A_cap, B_cap, [srcend, -32]
|
||||
stp C_cap, D_cap, [dst, 48]
|
||||
stp E_cap, F_cap, [tmp1_ptr, -64]
|
||||
str A_q, [dstend, -16]
|
||||
stp A_cap, B_cap, [tmp1_ptr, -32]
|
||||
ret
|
||||
|
||||
L(copy_long_backwards_cap):
|
||||
cbz tmp1, L(copy0)
|
||||
ldr D_q, [srcend, -16]
|
||||
and tmp1, xsrcend, 15
|
||||
#if defined(__CHERI_PURE_CAPABILITY__)
|
||||
alignd srcend, srcend, 4
|
||||
neg tmp2, tmp1
|
||||
add count, count, tmp2
|
||||
#else
|
||||
bic srcend, srcend, 15
|
||||
sub count, count, tmp1
|
||||
#endif
|
||||
ldp A_cap, B_cap, [srcend, -32]
|
||||
str D_q, [dstend, -16]
|
||||
ldp C_cap, D_cap, [srcend, -64]
|
||||
#if defined(__CHERI_PURE_CAPABILITY__)
|
||||
add dstend, dstend, tmp2 /* tmp1 was negated above to tmp2. */
|
||||
#else
|
||||
sub dstend, dstend, tmp1
|
||||
#endif
|
||||
subs count, count, 128
|
||||
b.ls L(copy64_from_start)
|
||||
|
||||
L(loop64_backwards_cap):
|
||||
str B_cap, [dstend, -16]
|
||||
str A_cap, [dstend, -32]
|
||||
ldp A_cap, B_cap, [srcend, -96]
|
||||
str D_cap, [dstend, -48]
|
||||
str C_cap, [dstend, -64]!
|
||||
ldp C_cap, D_cap, [srcend, -128]
|
||||
sub srcend, srcend, 64
|
||||
subs count, count, 64
|
||||
b.hi L(loop64_backwards_cap)
|
||||
|
||||
/* Write the last iteration and copy 64 bytes from the start. */
|
||||
L(copy64_from_start_cap):
|
||||
ldr A_q, [src]
|
||||
add src, src, auoff /* align up src to 16 bytes */
|
||||
add tmp1_ptr, dstin, auoff /* align up dstin to 16 bytes */
|
||||
ldp E_cap, F_cap, [src, 32]
|
||||
stp A_cap, B_cap, [dstend, -32]
|
||||
ldp A_cap, B_cap, [src]
|
||||
stp C_cap, D_cap, [dstend, -64]
|
||||
stp E_cap, F_cap, [tmp1_ptr, 32]
|
||||
str A_q, [dstin]
|
||||
stp A_cap, B_cap, [tmp1_ptr]
|
||||
ret
|
||||
|
||||
L(memcpy_nocap):
|
||||
cmp count, 128
|
||||
b.hi L(copy_long)
|
||||
cmp count, 32
|
||||
b.hi L(copy32_128)
|
||||
|
||||
L(copy32):
|
||||
/* Small copies: 16..32 bytes. */
|
||||
/* Note the 0..15 case is already handled at the start of memcpy */
|
||||
ldr A_q, [src]
|
||||
ldr B_q, [srcend, -16]
|
||||
str A_q, [dstin]
|
||||
str B_q, [dstend, -16]
|
||||
ret
|
||||
|
||||
/* Copy 8-15 bytes. */
|
||||
L(copy16):
|
||||
tbz count, 3, L(copy8)
|
||||
ldr A_l, [src]
|
||||
ldr A_h, [srcend, -8]
|
||||
str A_l, [dstin]
|
||||
str A_h, [dstend, -8]
|
||||
ret
|
||||
|
||||
.p2align 3
|
||||
/* Copy 4-7 bytes. */
|
||||
L(copy8):
|
||||
tbz count, 2, L(copy4)
|
||||
ldr A_lw, [src]
|
||||
ldr B_lw, [srcend, -4]
|
||||
str A_lw, [dstin]
|
||||
str B_lw, [dstend, -4]
|
||||
ret
|
||||
|
||||
/* Copy 0..3 bytes using a branchless sequence. */
|
||||
L(copy4):
|
||||
cbz count, L(copy0)
|
||||
lsr tmp1, count, 1
|
||||
ldrb A_lw, [src]
|
||||
ldrb C_lw, [srcend, -1]
|
||||
ldrb B_lw, [src, tmp1]
|
||||
strb A_lw, [dstin]
|
||||
strb B_lw, [dstin, tmp1]
|
||||
strb C_lw, [dstend, -1]
|
||||
L(copy0):
|
||||
ret
|
||||
|
||||
.p2align 4
|
||||
/* Medium copies: 33..128 bytes. */
|
||||
L(copy32_128):
|
||||
ldp A_q, B_q, [src]
|
||||
ldp C_q, D_q, [srcend, -32]
|
||||
cmp count, 64
|
||||
b.hi L(copy128)
|
||||
stp A_q, B_q, [dstin]
|
||||
stp C_q, D_q, [dstend, -32]
|
||||
ret
|
||||
|
||||
.p2align 4
|
||||
/* Copy 65..128 bytes. */
|
||||
L(copy128):
|
||||
ldp E_q, F_q, [src, 32]
|
||||
cmp count, 96
|
||||
b.ls L(copy96)
|
||||
ldp G_q, H_q, [srcend, -64]
|
||||
stp G_q, H_q, [dstend, -64]
|
||||
L(copy96):
|
||||
stp A_q, B_q, [dstin]
|
||||
stp E_q, F_q, [dstin, 32]
|
||||
stp C_q, D_q, [dstend, -32]
|
||||
ret
|
||||
|
||||
/* Copy more than 128 bytes. */
|
||||
L(copy_long):
|
||||
/* Use backwards copy if there is an overlap. */
|
||||
sub tmp1, xdstin, xsrc
|
||||
cmp tmp1, count
|
||||
b.lo L(copy_long_backwards)
|
||||
|
||||
/* Copy 16 bytes and then align src to 16-byte alignment. */
|
||||
ldr D_q, [src]
|
||||
and tmp1, xsrc, 15
|
||||
#if defined(__CHERI_PURE_CAPABILITY__)
|
||||
alignd src, src, 4
|
||||
neg tmp2, tmp1
|
||||
add dst, dstin, tmp2
|
||||
#else
|
||||
bic src, src, 15
|
||||
sub dst, dstin, tmp1
|
||||
#endif
|
||||
add count, count, tmp1 /* Count is now 16 too large. */
|
||||
ldp A_q, B_q, [src, 16]
|
||||
str D_q, [dstin]
|
||||
ldp C_q, D_q, [src, 48]
|
||||
subs count, count, 128 + 16 /* Test and readjust count. */
|
||||
b.ls L(copy64_from_end)
|
||||
L(loop64):
|
||||
stp A_q, B_q, [dst, 16]
|
||||
ldp A_q, B_q, [src, 80]
|
||||
stp C_q, D_q, [dst, 48]
|
||||
ldp C_q, D_q, [src, 112]
|
||||
add src, src, 64
|
||||
add dst, dst, 64
|
||||
subs count, count, 64
|
||||
b.hi L(loop64)
|
||||
|
||||
/* Write the last iteration and copy 64 bytes from the end. */
|
||||
L(copy64_from_end):
|
||||
ldp E_q, F_q, [srcend, -64]
|
||||
stp A_q, B_q, [dst, 16]
|
||||
ldp A_q, B_q, [srcend, -32]
|
||||
stp C_q, D_q, [dst, 48]
|
||||
stp E_q, F_q, [dstend, -64]
|
||||
stp A_q, B_q, [dstend, -32]
|
||||
ret
|
||||
|
||||
/* Large backwards copy for overlapping copies.
|
||||
Copy 16 bytes and then align srcend to 16-byte alignment. */
|
||||
L(copy_long_backwards):
|
||||
cbz tmp1, L(copy0)
|
||||
ldr D_q, [srcend, -16]
|
||||
and tmp1, xsrcend, 15
|
||||
#if defined(__CHERI_PURE_CAPABILITY__)
|
||||
alignd srcend, srcend, 4
|
||||
neg tmp2, tmp1
|
||||
add count, count, tmp2
|
||||
#else
|
||||
bic srcend, srcend, 15
|
||||
sub count, count, tmp1
|
||||
#endif
|
||||
ldp A_q, B_q, [srcend, -32]
|
||||
str D_q, [dstend, -16]
|
||||
ldp C_q, D_q, [srcend, -64]
|
||||
#if defined(__CHERI_PURE_CAPABILITY__)
|
||||
add dstend, dstend, tmp2 /* tmp1 was already negated above. */
|
||||
#else
|
||||
sub dstend, dstend, tmp1
|
||||
#endif
|
||||
subs count, count, 128
|
||||
b.ls L(copy64_from_start)
|
||||
|
||||
L(loop64_backwards):
|
||||
str B_q, [dstend, -16]
|
||||
str A_q, [dstend, -32]
|
||||
ldp A_q, B_q, [srcend, -96]
|
||||
str D_q, [dstend, -48]
|
||||
str C_q, [dstend, -64]!
|
||||
ldp C_q, D_q, [srcend, -128]
|
||||
sub srcend, srcend, 64
|
||||
subs count, count, 64
|
||||
b.hi L(loop64_backwards)
|
||||
|
||||
/* Write the last iteration and copy 64 bytes from the start. */
|
||||
L(copy64_from_start):
|
||||
ldp E_q, F_q, [src, 32]
|
||||
stp A_q, B_q, [dstend, -32]
|
||||
ldp A_q, B_q, [src]
|
||||
stp C_q, D_q, [dstend, -64]
|
||||
stp E_q, F_q, [dstin, 32]
|
||||
stp A_q, B_q, [dstin]
|
||||
ret
|
||||
|
||||
END (MEMCPY)
|
||||
|
||||
weak_alias (MEMCPY, MEMMOVE)
|
||||
libc_hidden_builtin_def (MEMCPY)
|
||||
libc_hidden_builtin_def (MEMMOVE)
|
||||
@@ -0,0 +1,32 @@
|
||||
/* Simple memrchr.
|
||||
|
||||
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; see the file COPYING.LIB. If
|
||||
not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void *__memrchr (const void *s, int c, size_t n)
|
||||
{
|
||||
unsigned char uc = c;
|
||||
const unsigned char *us = s;
|
||||
while (n-- > 0)
|
||||
if (us[n] == uc)
|
||||
return (void *) (us + n);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
weak_alias (__memrchr, memrchr)
|
||||
@@ -0,0 +1,154 @@
|
||||
/* 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>
|
||||
|
||||
#ifndef MEMSET
|
||||
# define MEMSET memset
|
||||
#endif
|
||||
|
||||
/* Assumptions:
|
||||
*
|
||||
* ARMv8-a, AArch64, Morello, Advanced SIMD, unaligned accesses.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(__CHERI_PURE_CAPABILITY__)
|
||||
#define dstin c0
|
||||
#define val x1
|
||||
#define valw w1
|
||||
#define count x2
|
||||
#define dst c3
|
||||
#define xdst x3
|
||||
#define dstend c4
|
||||
#define xdstend x4
|
||||
#define zva_val x5
|
||||
#else
|
||||
#define dstin x0
|
||||
#define val x1
|
||||
#define valw w1
|
||||
#define count x2
|
||||
#define dst x3
|
||||
#define xdst x3
|
||||
#define dstend x4
|
||||
#define xdstend x4
|
||||
#define zva_val x5
|
||||
#endif
|
||||
|
||||
ENTRY (MEMSET)
|
||||
PTR_ARG (0)
|
||||
SIZE_ARG (2)
|
||||
|
||||
dup v0.16B, valw
|
||||
add dstend, dstin, count
|
||||
|
||||
cmp count, 96
|
||||
b.hi L(set_long)
|
||||
cmp count, 16
|
||||
b.hs L(set_medium)
|
||||
mov val, v0.D[0]
|
||||
|
||||
/* Set 0..15 bytes. */
|
||||
tbz count, 3, 1f
|
||||
str val, [dstin]
|
||||
str val, [dstend, -8]
|
||||
ret
|
||||
.p2align 4
|
||||
1: tbz count, 2, 2f
|
||||
str valw, [dstin]
|
||||
str valw, [dstend, -4]
|
||||
ret
|
||||
2: cbz count, 3f
|
||||
strb valw, [dstin]
|
||||
tbz count, 1, 3f
|
||||
strh valw, [dstend, -2]
|
||||
3: ret
|
||||
|
||||
/* Set 17..96 bytes. */
|
||||
L(set_medium):
|
||||
str q0, [dstin]
|
||||
tbnz count, 6, L(set96)
|
||||
str q0, [dstend, -16]
|
||||
tbz count, 5, 1f
|
||||
str q0, [dstin, 16]
|
||||
str q0, [dstend, -32]
|
||||
1: ret
|
||||
|
||||
.p2align 4
|
||||
/* Set 64..96 bytes. Write 64 bytes from the start and
|
||||
32 bytes from the end. */
|
||||
L(set96):
|
||||
str q0, [dstin, 16]
|
||||
stp q0, q0, [dstin, 32]
|
||||
stp q0, q0, [dstend, -32]
|
||||
ret
|
||||
|
||||
.p2align 4
|
||||
L(set_long):
|
||||
and valw, valw, 255
|
||||
#if defined(__CHERI_PURE_CAPABILITY__)
|
||||
alignd dst, dstin, 4
|
||||
#else
|
||||
bic dst, dstin, 15
|
||||
#endif
|
||||
str q0, [dstin]
|
||||
cmp count, 160
|
||||
ccmp valw, 0, 0, hs
|
||||
b.ne L(no_zva)
|
||||
|
||||
#ifndef SKIP_ZVA_CHECK
|
||||
mrs zva_val, dczid_el0
|
||||
and zva_val, zva_val, 31
|
||||
cmp zva_val, 4 /* ZVA size is 64 bytes. */
|
||||
b.ne L(no_zva)
|
||||
#endif
|
||||
str q0, [dst, 16]
|
||||
stp q0, q0, [dst, 32]
|
||||
#if defined(__CHERI_PURE_CAPABILITY__)
|
||||
alignd dst, dst, 6
|
||||
#else
|
||||
bic dst, dst, 63
|
||||
#endif
|
||||
sub count, xdstend, xdst /* Count is now 64 too large. */
|
||||
sub count, count, 128 /* Adjust count and bias for loop. */
|
||||
|
||||
.p2align 4
|
||||
L(zva_loop):
|
||||
add dst, dst, 64
|
||||
dc zva, dst
|
||||
subs count, count, 64
|
||||
b.hi L(zva_loop)
|
||||
stp q0, q0, [dstend, -64]
|
||||
stp q0, q0, [dstend, -32]
|
||||
ret
|
||||
|
||||
L(no_zva):
|
||||
sub count, xdstend, xdst /* Count is 16 too large. */
|
||||
sub dst, dst, 16 /* Dst is biased by -32. */
|
||||
sub count, count, 64 + 16 /* Adjust count and bias for loop. */
|
||||
L(no_zva_loop):
|
||||
stp q0, q0, [dst, 32]
|
||||
stp q0, q0, [dst, 64]!
|
||||
subs count, count, 64
|
||||
b.hi L(no_zva_loop)
|
||||
stp q0, q0, [dstend, -64]
|
||||
stp q0, q0, [dstend, -32]
|
||||
ret
|
||||
|
||||
END (MEMSET)
|
||||
libc_hidden_builtin_def (MEMSET)
|
||||
@@ -0,0 +1,43 @@
|
||||
/* rawmemchr - find a character in a memory zone
|
||||
|
||||
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>
|
||||
|
||||
/* Special case rawmemchr (s, 0) as strlen, otherwise tailcall memchr.
|
||||
Call strlen without setting up a full frame - it preserves x14/x15.
|
||||
*/
|
||||
|
||||
ENTRY (__rawmemchr)
|
||||
|
||||
cbz w1, L(do_strlen)
|
||||
mov x2, -1
|
||||
b __memchr
|
||||
|
||||
L(do_strlen):
|
||||
mov c15, c30
|
||||
cfi_return_column (c15)
|
||||
mov c14, c0
|
||||
bl __strlen
|
||||
add c0, c14, x0
|
||||
ret c15
|
||||
|
||||
END (__rawmemchr)
|
||||
weak_alias (__rawmemchr, rawmemchr)
|
||||
libc_hidden_builtin_def (__rawmemchr)
|
||||
@@ -0,0 +1,64 @@
|
||||
/* 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>
|
||||
|
||||
/* Keep traditional entry points in with sigsetjmp(). */
|
||||
ENTRY (setjmp)
|
||||
mov x1, #1
|
||||
b 1f
|
||||
END (setjmp)
|
||||
|
||||
ENTRY (_setjmp)
|
||||
mov x1, #0
|
||||
b 1f
|
||||
END (_setjmp)
|
||||
libc_hidden_def (_setjmp)
|
||||
|
||||
ENTRY (__sigsetjmp)
|
||||
1:
|
||||
stp c19, c20, [c0, #JB_X19<<4]
|
||||
stp c21, c22, [c0, #JB_X21<<4]
|
||||
stp c23, c24, [c0, #JB_X23<<4]
|
||||
stp c25, c26, [c0, #JB_X25<<4]
|
||||
stp c27, c28, [c0, #JB_X27<<4]
|
||||
stp c29, c30, [c0, #JB_X29<<4]
|
||||
|
||||
/* setjmp probe takes 3 arguments, address of jump buffer
|
||||
first argument (8@x0), return value second argument (-4@x1),
|
||||
and target address (8@x30), respectively. */
|
||||
LIBC_PROBE (setjmp, 3, 8@c0, -4@c1, 8@c30)
|
||||
stp q8, q9, [c0, #JB_D8<<4]
|
||||
stp q10, q11, [c0, #JB_D10<<4]
|
||||
stp q12, q13, [c0, #JB_D12<<4]
|
||||
stp q14, q15, [c0, #JB_D14<<4]
|
||||
|
||||
mov c2, csp
|
||||
str c2, [c0, #JB_SP<<4]
|
||||
|
||||
#if IS_IN (rtld)
|
||||
/* In ld.so we never save the signal mask */
|
||||
mov w0, #0
|
||||
RET
|
||||
#else
|
||||
b C_SYMBOL_NAME(__sigjmp_save)
|
||||
#endif
|
||||
END (__sigsetjmp)
|
||||
hidden_def (__sigsetjmp)
|
||||
@@ -0,0 +1,216 @@
|
||||
/* 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 <linux/auxvec.h>
|
||||
#include <cheri_perms.h>
|
||||
|
||||
weak_extern (__rela_dyn_start)
|
||||
weak_extern (__rela_dyn_end)
|
||||
|
||||
/* This is the canonical entry point, usually the first thing in the text
|
||||
segment.
|
||||
|
||||
Note that the code in the .init section has already been run.
|
||||
This includes _init and _libc_init
|
||||
|
||||
|
||||
At this entry point, most registers' values are unspecified, except:
|
||||
|
||||
x0/w0 Contains a function pointer to be registered with `atexit'.
|
||||
This is how the dynamic linker arranges to have DT_FINI
|
||||
functions called for shared libraries that have been loaded
|
||||
before this code runs.
|
||||
|
||||
sp The stack contains the arguments and environment:
|
||||
0(sp) argc
|
||||
8(sp) argv[0]
|
||||
...
|
||||
(8*argc)(sp) NULL
|
||||
(8*(argc+1))(sp) envp[0]
|
||||
...
|
||||
NULL
|
||||
*/
|
||||
|
||||
.text
|
||||
ENTRY(_start)
|
||||
|
||||
/* Create an initial frame with 0 LR and FP */
|
||||
cfi_undefined (c30)
|
||||
mov c29, czr
|
||||
mov c30, czr
|
||||
|
||||
/* TODO: Use the presence of __rela_dyn_start. */
|
||||
mov c5, c0
|
||||
cbnz x0, L(rtld_done)
|
||||
|
||||
/* Initialize capabilities. */
|
||||
#ifndef SHARED
|
||||
/* The GNU Linker emits a R_MORELLO_RELATIVE relocation along with
|
||||
__rela_dyn_start and __rela_dyn_end symbols around the relocation section.
|
||||
r_offset contains the location, size and permissions:
|
||||
|
||||
capability location // offset 0 (64 bits)
|
||||
length // offset 8 (56 bits)
|
||||
permissions // (8 bits)
|
||||
addend (capability offset) // offset 16
|
||||
|
||||
according to the ABI document in:
|
||||
https://github.com/ARM-software/abi-aa/blob/main/aaelf64-morello/aaelf64-morello.rst#dynamic-linking-with-morello
|
||||
|
||||
The addend is the capability offset.
|
||||
|
||||
Note that this will not work with clang, since lld emits a __cap_relocs
|
||||
struct that has a different layout. If we need to support clang+lld, then
|
||||
we need to copy the capability initialization steps from Bionic, in:
|
||||
libc/arch-morello/bionic/__morello_init_static.S. */
|
||||
|
||||
adrp c0, __rela_dyn_start
|
||||
add c0, c0, #:lo12:__rela_dyn_start
|
||||
adrp c1, __rela_dyn_end
|
||||
add c1, c1, #:lo12:__rela_dyn_end
|
||||
|
||||
1:
|
||||
/* No capabilities to initialize. Skip to stack adjustment. */
|
||||
cmp c0, c1
|
||||
b.eq 3f
|
||||
|
||||
/* Load the address of capability. */
|
||||
ldr x2, [c0, #0]
|
||||
|
||||
/* Construct capability location from DDC and r_offset. */
|
||||
cvtd c2, x2
|
||||
|
||||
/* Base in x3. */
|
||||
ldr x3, [c2]
|
||||
|
||||
/* Length + permissions in x5. */
|
||||
ldr x5, [c2, #8]
|
||||
|
||||
/* Permissions in x6. */
|
||||
lsr x6, x5, #56
|
||||
|
||||
/* Permissions encoded as:
|
||||
4 = X (executable)
|
||||
2 = W (read/write)
|
||||
1 = R (read only)
|
||||
|
||||
Permissions to clear in x8 and x11. */
|
||||
mov x8, (CAP_PERM_STORE_CAP | CAP_PERM_EXECUTE)
|
||||
movk x8, (CAP_PERM_STORE >> 16), lsl #16
|
||||
mov x9, (CAP_PERM_EXECUTE)
|
||||
mov x10, (CAP_PERM_STORE_CAP)
|
||||
movk x10, (CAP_PERM_STORE >> 16), lsl #16
|
||||
mov x11, (CAP_PERM_UNSEAL | CAP_PERM_SEAL | CAP_PERM_COMPARTMENT_ID)
|
||||
cmp x6, #0x2
|
||||
csel x8, x9, x8, eq
|
||||
cmp x6, #0x4
|
||||
csel x8, x10, x8, eq
|
||||
|
||||
/* Length in x5. */
|
||||
and x5, x5, #0xffffffffffffff
|
||||
|
||||
/* Offset in x7. */
|
||||
ldr x7, [c0, #16]
|
||||
|
||||
/* Construct capability from DDC with value equal to base. */
|
||||
cvtd c3, x3
|
||||
|
||||
/* Set bounds to [base ; base + length]. */
|
||||
scbndse c3, c3, x5
|
||||
|
||||
/* Compute the capability value from addend. */
|
||||
add c3, c3, x7
|
||||
|
||||
/* Clear permissions. */
|
||||
clrperm c3, c3, x8
|
||||
clrperm c3, c3, x11
|
||||
|
||||
/* Seal capabilities, which provide execute permission, with MORELLO_RB */
|
||||
tst x8, #CAP_PERM_EXECUTE
|
||||
b.ne 2f
|
||||
|
||||
seal c3, c3, rb
|
||||
|
||||
2:
|
||||
/* Store the constructed capability to the target location. */
|
||||
str c3, [c2]
|
||||
|
||||
/* Move to the next __rela_dyn entry. */
|
||||
add c0, c0, #24
|
||||
b 1b
|
||||
|
||||
3:
|
||||
#endif /* !SHARED */
|
||||
|
||||
/* Setup rtld_fini in argument register */
|
||||
mov c5, czr
|
||||
|
||||
L(rtld_done):
|
||||
|
||||
/* Load argc and a pointer to argv */
|
||||
ldr c1, [csp, #0]
|
||||
add c2, csp, #16
|
||||
|
||||
/* Setup stack limit in argument register */
|
||||
mov c6, csp
|
||||
|
||||
#ifdef PIC
|
||||
# ifdef SHARED
|
||||
adrp c0, :got:main
|
||||
ldr c0, [c0, #:got_lo12:main]
|
||||
# else
|
||||
adrp c0, __wrap_main
|
||||
add c0, c0, :lo12:__wrap_main
|
||||
# endif /* SHARED */
|
||||
#else
|
||||
/* Set up the other arguments in registers */
|
||||
MOVL (0, main)
|
||||
cvtd c0, x0
|
||||
#endif /* PIC */
|
||||
|
||||
mov x3, #0 /* Used to be init. */
|
||||
mov x4, #0 /* Used to be fini. */
|
||||
|
||||
/* __libc_start_main (main, argc, argv, init, fini, rtld_fini,
|
||||
stack_end) */
|
||||
|
||||
/* Let the libc call main and exit with its return code. */
|
||||
bl __libc_start_main
|
||||
|
||||
/* should never get here....*/
|
||||
bl abort
|
||||
END(_start)
|
||||
|
||||
#if defined PIC && !defined SHARED
|
||||
/* When main is not defined in the executable but in a shared library
|
||||
then a wrapper is needed in crt1.o of the static-pie enabled libc,
|
||||
because crt1.o and rcrt1.o share code and the later must avoid the
|
||||
use of GOT relocations before __libc_start_main is called. */
|
||||
ENTRY(__wrap_main)
|
||||
b main
|
||||
END(__wrap_main)
|
||||
#endif
|
||||
|
||||
/* Define a symbol for the first piece of initialized data. */
|
||||
.data
|
||||
.globl __data_start
|
||||
__data_start:
|
||||
.long 0
|
||||
.weak data_start
|
||||
data_start = __data_start
|
||||
@@ -0,0 +1,34 @@
|
||||
/* Simple stpcpy.
|
||||
|
||||
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; see the file COPYING.LIB. If
|
||||
not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#define NO_MEMPCPY_STPCPY_REDIRECT
|
||||
#include <string.h>
|
||||
|
||||
#undef stpcpy
|
||||
#undef __stpcpy
|
||||
|
||||
char *__stpcpy (char *d, const char *s)
|
||||
{
|
||||
size_t n = strlen (s);
|
||||
return memcpy (d, s, n+1) + n;
|
||||
}
|
||||
|
||||
weak_alias (__stpcpy, stpcpy)
|
||||
libc_hidden_def (__stpcpy)
|
||||
libc_hidden_builtin_def (stpcpy)
|
||||
@@ -0,0 +1,33 @@
|
||||
/* Simple strchr.
|
||||
|
||||
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; see the file COPYING.LIB. If
|
||||
not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
char *strchr (const char *s, int c)
|
||||
{
|
||||
unsigned char uc = c;
|
||||
const unsigned char *us = (const unsigned char *) s;
|
||||
for (; *us != uc; us++)
|
||||
if (*us == 0)
|
||||
return NULL;
|
||||
return (char *) us;
|
||||
}
|
||||
|
||||
weak_alias (strchr, index)
|
||||
libc_hidden_builtin_def (strchr)
|
||||
@@ -0,0 +1,30 @@
|
||||
/* Simple strchrnul.
|
||||
|
||||
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; see the file COPYING.LIB. If
|
||||
not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
char *__strchrnul (const char *s, int c)
|
||||
{
|
||||
unsigned char uc = c;
|
||||
const unsigned char *us = (const unsigned char *) s;
|
||||
for (; *us != uc && *us != 0; us++);
|
||||
return (char *) us;
|
||||
}
|
||||
|
||||
weak_alias (__strchrnul, strchrnul)
|
||||
@@ -0,0 +1,30 @@
|
||||
/* Simple strcmp.
|
||||
|
||||
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; see the file COPYING.LIB. If
|
||||
not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
int strcmp(const char *s1, const char *s2)
|
||||
{
|
||||
const unsigned char *us1 = (const unsigned char *) s1;
|
||||
const unsigned char *us2 = (const unsigned char *) s2;
|
||||
for (; *us1 == *us2 && *us1 != 0; us1++, us2++);
|
||||
return *us1 - *us2;
|
||||
}
|
||||
|
||||
libc_hidden_builtin_def (strcmp)
|
||||
@@ -0,0 +1,28 @@
|
||||
/* Simple strcpy.
|
||||
|
||||
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; see the file COPYING.LIB. If
|
||||
not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
char *strcpy (char *d, const char *s)
|
||||
{
|
||||
size_t n = strlen (s);
|
||||
return memcpy (d, s, n+1);
|
||||
}
|
||||
|
||||
libc_hidden_builtin_def (strcpy)
|
||||
@@ -0,0 +1,35 @@
|
||||
/* Simple strcspn.
|
||||
|
||||
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 <string.h>
|
||||
|
||||
size_t strcspn (const char *str, const char *reject)
|
||||
{
|
||||
if (reject[0] == 0 || reject[1] == 0)
|
||||
return __strchrnul (str, reject[0]) - str;
|
||||
|
||||
unsigned char table[256] = {0};
|
||||
unsigned char *us;
|
||||
for (us = (unsigned char*) reject; *us != 0; table[*us++] = 1);
|
||||
table[*us] = 1;
|
||||
|
||||
for (us = (unsigned char*) str; table[*us] == 0; us++);
|
||||
return us - (unsigned char *) str;
|
||||
}
|
||||
libc_hidden_builtin_def (strcspn)
|
||||
@@ -0,0 +1,30 @@
|
||||
/* Simple strlen.
|
||||
|
||||
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; see the file COPYING.LIB. If
|
||||
not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
size_t __strlen (const char *s)
|
||||
{
|
||||
size_t n;
|
||||
for (n = 0; s[n] != 0; n++);
|
||||
return n;
|
||||
}
|
||||
|
||||
weak_alias (__strlen, strlen)
|
||||
libc_hidden_builtin_def (strlen)
|
||||
@@ -0,0 +1,32 @@
|
||||
/* Simple strncmp.
|
||||
|
||||
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; see the file COPYING.LIB. If
|
||||
not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
int strncmp(const char *s1, const char *s2, size_t n)
|
||||
{
|
||||
const unsigned char *us1 = (const unsigned char *) s1;
|
||||
const unsigned char *us2 = (const unsigned char *) s2;
|
||||
for (; n > 0; us1++, us2++, n--)
|
||||
if (*us1 != *us2 || *us1 == 0)
|
||||
return *us1 - *us2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
libc_hidden_builtin_def (strncmp)
|
||||
@@ -0,0 +1,31 @@
|
||||
/* Simple strnlen.
|
||||
|
||||
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; see the file COPYING.LIB. If
|
||||
not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
size_t __strnlen (const char *s, size_t m)
|
||||
{
|
||||
size_t n;
|
||||
for (n = 0; n < m && s[n] != 0; n++);
|
||||
return n;
|
||||
}
|
||||
|
||||
weak_alias (__strnlen, strnlen)
|
||||
libc_hidden_def (__strnlen)
|
||||
libc_hidden_def (strnlen)
|
||||
@@ -0,0 +1,29 @@
|
||||
/* Simple strrchr.
|
||||
|
||||
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; see the file COPYING.LIB. If
|
||||
not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
char *strrchr (const char *s, int c)
|
||||
{
|
||||
size_t n = strlen (s) + 1;
|
||||
return __memrchr (s, c, n);
|
||||
}
|
||||
|
||||
weak_alias (strrchr, rindex)
|
||||
libc_hidden_builtin_def (strrchr)
|
||||
@@ -0,0 +1,40 @@
|
||||
/* Simple strspn.
|
||||
|
||||
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 <string.h>
|
||||
|
||||
size_t strspn (const char *str, const char *accept)
|
||||
{
|
||||
if (accept[0] == 0)
|
||||
return 0;
|
||||
if (accept[1] == 0)
|
||||
{
|
||||
const char *p;
|
||||
for (p = str; *p == accept[0]; p++);
|
||||
return p - str;
|
||||
}
|
||||
|
||||
unsigned char table[256] = {0};
|
||||
unsigned char *us;
|
||||
for (us = (unsigned char*) accept; *us != 0; table[*us++] = 1);
|
||||
|
||||
for (us = (unsigned char*) str; table[*us] != 0; us++);
|
||||
return us - (unsigned char *) str;
|
||||
}
|
||||
libc_hidden_builtin_def (strspn)
|
||||
@@ -0,0 +1,19 @@
|
||||
#include <stddef.h>
|
||||
#include <sysdep.h>
|
||||
#include <tls.h>
|
||||
#include <link.h>
|
||||
#include <dl-tlsdesc.h>
|
||||
|
||||
--
|
||||
|
||||
-- Abuse tls.h macros to derive offsets relative to the thread register.
|
||||
|
||||
TLSDESC_ARG offsetof(struct tlsdesc, arg)
|
||||
|
||||
TLSDESC_GEN_COUNT offsetof(struct tlsdesc_dynamic_arg, gen_count)
|
||||
TLSDESC_MODID offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_module)
|
||||
TLSDESC_MODOFF offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_offset)
|
||||
TLSDESC_SIZE offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_size)
|
||||
TCBHEAD_DTV offsetof(tcbhead_t, dtv)
|
||||
DTV_COUNTER offsetof(dtv_t, counter)
|
||||
TLS_DTV_UNALLOCATED TLS_DTV_UNALLOCATED
|
||||
@@ -35,4 +35,6 @@
|
||||
bool __attribute__((unused)) mte = \
|
||||
MTE_ENABLED (); \
|
||||
bool __attribute__((unused)) sve = \
|
||||
GLRO(dl_aarch64_cpu_features).sve;
|
||||
GLRO(dl_aarch64_cpu_features).sve; \
|
||||
bool __attribute__((unused)) morello = \
|
||||
GLRO(dl_hwcap2) & HWCAP2_MORELLO;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user