summaryrefslogtreecommitdiff
path: root/lib/mlibc/options/lsb/generic/auxv.cpp
blob: a4d2c8f24c57448dc3c127093c81207068eccfbc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

#include <errno.h>
#include <stdint.h>
#include <sys/auxv.h>

#include <bits/ensure.h>

extern "C" uintptr_t *__dlapi_entrystack();

int peekauxval(unsigned long type, unsigned long *out) {
	// Find the auxiliary vector by skipping args and environment.
	auto aux = __dlapi_entrystack();
	aux += *aux + 1; // Skip argc and all arguments
	__ensure(!*aux);
	aux++;
	while(*aux) // Now, we skip the environment.
		aux++;
	aux++;

	// Parse the auxiliary vector.
	while(true) {
		auto value = aux + 1;
		if(*aux == AT_NULL) {
			errno = ENOENT;
			return -1;
		}else if(*aux == type) {
			*out = *value;
			return 0;
		}
		aux += 2;
	}
}

unsigned long getauxval(unsigned long type) {
	unsigned long value = 0;
	if(peekauxval(type, &value))
		return 0;
	return value;
}

// XXX(qookie):
// This is here because libgcc will call into __getauxval on glibc Linux
// (which is what it believes we are due to the aarch64-linux-gnu toolchain)
// in order to find AT_HWCAP to discover if LSE atomics are supported.
//
// This is not necessary on a custom Linux toolchain and is purely an artifact of
// using the host toolchain.

// __gnu_linux__ is the define checked by libgcc
#if defined(__aarch64__) && defined(__gnu_linux__)

extern "C" unsigned long __getauxval(unsigned long type) {
	unsigned long value = 0;
	if(peekauxval(type, &value))
		return 0;
	return value;
}

#endif