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 realloc __libc_realloc
#define free __libc_free #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 MAXP2(a,b) (-(-(a)&-(b)))
#define ALIGN(x,y) ((x)+(y)-1 & -(y)) #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"); env_preload = getenv("LD_PRELOAD");
} }
/* Activate error handler function */
error = error_impl;
/* If the main program was already loaded by the kernel, /* If the main program was already loaded by the kernel,
* AT_PHDR will point to some location other than the dynamic * AT_PHDR will point to some location other than the dynamic
* linker's program headers. */ * 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; return ret;
} }
static void error(const char *fmt, ...) static void error_impl(const char *fmt, ...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
@ -2361,3 +2366,7 @@ static void error(const char *fmt, ...)
__dl_vseterr(fmt, ap); __dl_vseterr(fmt, ap);
va_end(ap); va_end(ap);
} }
static void error_noop(const char *fmt, ...)
{
}