early stage ldso: remove symbolic references via error handling function

while the error handling function should not be reached in stage 2
(assuming ldso itself was linked correctly), this was not statically
determinate from the compiler's perspective, and in theory a compiler
performing LTO could lift the TLS references (errno and other things)
out of the printf-family functions called in a stage where TLS is not
yet initialized.

instead, perform the call via a static-storage, internal-linkage
function pointer which will be set to a no-op function until the stage
where the real error handling function should be reachable.

inspired by commit 63c67053a3.
This commit is contained in:
Rich Felker 2022-07-19 19:00:53 -04:00
parent 63c67053a3
commit d16d7b1099

View File

@ -29,7 +29,9 @@
#define realloc __libc_realloc
#define free __libc_free
static void error(const char *, ...);
static void error_impl(const char *, ...);
static void error_noop(const char *, ...);
static void (*error)(const char *, ...) = error_noop;
#define MAXP2(a,b) (-(-(a)&-(b)))
#define ALIGN(x,y) ((x)+(y)-1 & -(y))
@ -1758,6 +1760,9 @@ void __dls3(size_t *sp, size_t *auxv)
env_preload = getenv("LD_PRELOAD");
}
/* Activate error handler function */
error = error_impl;
/* If the main program was already loaded by the kernel,
* AT_PHDR will point to some location other than the dynamic
* linker's program headers. */
@ -2347,7 +2352,7 @@ int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void
return ret;
}
static void error(const char *fmt, ...)
static void error_impl(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
@ -2361,3 +2366,7 @@ static void error(const char *fmt, ...)
__dl_vseterr(fmt, ap);
va_end(ap);
}
static void error_noop(const char *fmt, ...)
{
}