Page MenuHomeFreeBSD

Export a weak __progname and environ symbol from libc.so
Needs ReviewPublic

Authored by arichardson on Jun 21 2021, 1:46 PM.
Tags
None
Referenced Files
Unknown Object (File)
Sat, Apr 6, 3:55 AM
Unknown Object (File)
Sun, Mar 31, 2:53 PM
Unknown Object (File)
Feb 28 2024, 11:45 AM
Unknown Object (File)
Jan 12 2024, 7:54 PM
Unknown Object (File)
Jan 12 2024, 2:09 AM
Unknown Object (File)
Dec 22 2023, 11:05 PM
Unknown Object (File)
Nov 15 2023, 9:44 PM
Unknown Object (File)
Nov 10 2023, 1:58 PM
Subscribers

Details

Summary

Not having libc.so provide these two variables means it is impossible
to link downstream code with -Wl,--no-undefined and/or
-Wl,--no-allow-shlib-undefined. The problem here is that the real
definition of these symbols is provided by the csu bits and is added to
the final executable. I believe that changing this to define them in
libc.so instead would not be backwards, so this commit adds a weak
definition in libc.so instead.

Currently, downstream projects that compile with -Wl,--no-undefined to
catch missing symbols have to manually opt-out for FreeBSD. See for
example https://codereview.qt-project.org/c/qt/qtbase/+/147845 or
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1306.

PR: 220103
MFC after: 1 week

Test Plan

I can now build QtBase with -Wl,--no-undefined + -Wl,--no-allow-shlib-undefined, before I got linker errors. Qt binaries also still run since environ is resolved from the main executable.

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 40015
Build 36904: arc lint + arc unit

Event Timeline

arichardson created this revision.

I do not like it, and in fact think that the drawbacks overweight the supposed benefit.

First, it would break things like dlsym(NULL, "environ") when done not from the main binary. Initially I thought that it would also break e.g. LD_PRELOAD=libc.so binary but it seems that it wouldn't any more than other cases.

Second, our interpretation of weak symbols at runtime as having lower precedence for interposing than non-weak symbols is non-standard. It is probably too late to try to fix that, but at least we should not introduce new cases of use.

Third, the references from DSO to envrion, linked with such libc, gets versioned. I did not looked how it is actually resolved, but I am surprised that it works for you. It should look for the versioned symbol and bind to libc one.

In D30842#694092, @kib wrote:

I do not like it, and in fact think that the drawbacks overweight the supposed benefit.

First, it would break things like dlsym(NULL, "environ") when done not from the main binary. Initially I thought that it would also break e.g. LD_PRELOAD=libc.so binary but it seems that it wouldn't any more than other cases.

Second, our interpretation of weak symbols at runtime as having lower precedence for interposing than non-weak symbols is non-standard. It is probably too late to try to fix that, but at least we should not introduce new cases of use.

Third, the references from DSO to envrion, linked with such libc, gets versioned. I did not looked how it is actually resolved, but I am surprised that it works for you. It should look for the versioned symbol and bind to libc one.

I don't like this approach either but it was the simplest solution I could think of that avoids having to patch downstream projects. I wonder if simply exporting an undef weak symbol from libc.so (without defining it) would also work.

I wonder if simply exporting an undef weak symbol from libc.so (without defining it) would also work.

This is not how symbol resolution work, no.

Is there a workaround for this?

Is there *any* way to get the environ value from a shared library?

In D30842#840632, @yuri wrote:

Is there a workaround for this?

Is there *any* way to get the environ value from a shared library?

Use getenv(3) and friends

In D30842#840640, @kib wrote:
In D30842#840632, @yuri wrote:

Is there a workaround for this?

Is there *any* way to get the environ value from a shared library?

Use getenv(3) and friends

getenv(3) doesn't return environ, instead it returns individual environment values.

Is it possible to retrieve the environ value in some other way?

In D30842#840641, @yuri wrote:
In D30842#840640, @kib wrote:
In D30842#840632, @yuri wrote:

Is there a workaround for this?

Is there *any* way to get the environ value from a shared library?

Use getenv(3) and friends

getenv(3) doesn't return environ, instead it returns individual environment values.

Is it possible to retrieve the environ value in some other way?

Why do you need it?

Anyway, dlsym(RTLD_DEFAULT, "environ") would get it.

#include <dlfcn.h>
#include <stdio.h>

extern char **environ;

int
main(void)
{
	printf("%p %p\n", &environ, dlsym(RTLD_DEFAULT, "environ"));
}