Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions cpython-unix/antiquator/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
lib*_placeholder.c
lib*_placeholder.versions
lib*_placeholder.so
*.o
*.a
glibc-*/
glibc_*.debian.tar.xz
glibc_*.dsc
glibc_*.orig.tar.xz
glibc_*.orig.tar.xz.asc
23 changes: 23 additions & 0 deletions cpython-unix/antiquator/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
GLIBC ?= glibc-2.39/

LIBS := libanl libc libdl libm libpthread libresolv librt libutil
HELPERS := elf-init.o libc_start_main.o

all: ${LIBS:=_placeholder.so} libantiquator_helpers.a(${HELPERS})

%.so: %.c %.versions
${CC} -fPIC -shared -o $@ $< -Wl,--version-script,$*.versions

${LIBS:=_placeholder.c} ${LIBS:=_placeholder.versions} &: make_shadow_libraries.py ${GLIBC}
./make_shadow_libraries.py ${GLIBC} .

clean:
-${RM} ${LIBS:=_placeholder.so} ${LIBS:=_placeholder.c} ${LIBS:=._placeholder.versions} libc_start_main.o

elf-init.o: CFLAGS += -I.

glibc-%/:
apt-get source glibc

.PHONY: all clean
.SECONDARY:
40 changes: 40 additions & 0 deletions cpython-unix/antiquator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
Antiquator - Use a newer glibc to build for older glibc versions
===

This is a set of utilities to enable building binaries using a newer
glibc that can run on older glibc versions: if a symbol exists in an
older version, prefer that implementation, and if a symbol does not
exist in an older version, enable weak linking against it (runtime value
is NULL if not found).

First, run `make` to build shadow libraries from glibc sources. If you
already have a glibc checkout, you can use `make GLIBC=/path/to/glibc`.
This should be as new as your compile-time glibc; newer will probably
work fine but is probably not helpful, since you won't pick up any
symbols from it.

Then set the `antiquator` environment variable to this directory. (This
needs to be an exported environment variable.)

Finally, use `gcc -specs ${antiquator}/gcc.spec` or `clang --config
${antiquator}/clang.config` for compiling and linking (e.g. add those options
to `CFLAGS` and `LDFLAGS`).

The clang implementation uses `-fuse-ld` internally; to pick the actual
linker, you can use `-Wl,-fuse-ld=...`.

Requirements
---

You need a relatively recent toolchain (at least binutils 2.35+) and
patchelf.

lld seems to not work as a linker. This might be an lld bug. (bfd ld and
gold both seem to work.)

Credits
---

elf-init.c is taken from glibc 2.33, the last version that had it. It is
unmodified from the version that was in glibc and used under the license
exception stated in the file.
7 changes: 7 additions & 0 deletions cpython-unix/antiquator/bits/mman-shared.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include_next <bits/mman-shared.h>

#define weaken(sym) extern __typeof(sym) sym __attribute__((weak))

#ifdef _GNU_SOURCE
weaken(memfd_create);
#endif
2 changes: 2 additions & 0 deletions cpython-unix/antiquator/clang.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-isystem <CFGDIR>
-fuse-ld=<CFGDIR>/wrap-linker
107 changes: 107 additions & 0 deletions cpython-unix/antiquator/elf-init.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/* Startup support for ELF initializers/finalizers in the main executable.
Copyright (C) 2002-2021 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/>. */

#include <stddef.h>
#include <elf-initfini.h>


/* These magic symbols are provided by the linker. */
extern void (*__preinit_array_start []) (int, char **, char **)
attribute_hidden;
extern void (*__preinit_array_end []) (int, char **, char **)
attribute_hidden;
extern void (*__init_array_start []) (int, char **, char **)
attribute_hidden;
extern void (*__init_array_end []) (int, char **, char **)
attribute_hidden;
extern void (*__fini_array_start []) (void) attribute_hidden;
extern void (*__fini_array_end []) (void) attribute_hidden;


#if ELF_INITFINI
/* These function symbols are provided for the .init/.fini section entry
points automagically by the linker. */
extern void _init (void);
extern void _fini (void);
#endif


/* These functions are passed to __libc_start_main by the startup code.
These get statically linked into each program. For dynamically linked
programs, this module will come from libc_nonshared.a and differs from
the libc.a module in that it doesn't call the preinit array. */


void
__libc_csu_init (int argc, char **argv, char **envp)
{
/* For dynamically linked executables the preinit array is executed by
the dynamic linker (before initializing any shared object). */

#ifndef LIBC_NONSHARED
/* For static executables, preinit happens right before init. */
{
const size_t size = __preinit_array_end - __preinit_array_start;
size_t i;
for (i = 0; i < size; i++)
(*__preinit_array_start [i]) (argc, argv, envp);
}
#endif

#if ELF_INITFINI
_init ();
#endif

const size_t size = __init_array_end - __init_array_start;
for (size_t i = 0; i < size; i++)
(*__init_array_start [i]) (argc, argv, envp);
}

/* This function should not be used anymore. We run the executable's
destructor now just like any other. We cannot remove the function,
though. */
void
__libc_csu_fini (void)
{
#ifndef LIBC_NONSHARED
size_t i = __fini_array_end - __fini_array_start;
while (i-- > 0)
(*__fini_array_start [i]) ();

# if ELF_INITFINI
_fini ();
# endif
#endif
}
9 changes: 9 additions & 0 deletions cpython-unix/antiquator/elf-initfini.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Somewhat confusing name - this means "this code is going into
// libc_nonshared.a", the library of static code that is linked when
// you're using libc.so. So effectively it means you _are_ targeting a
// shared link and not a static link.
#define LIBC_NONSHARED 1

#define ELF_INITFINI 1

#define attribute_hidden __attribute__((visibility("hidden")))
37 changes: 37 additions & 0 deletions cpython-unix/antiquator/gcc.specs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Spec file for GCC. `gcc -specs antiquator.spec`
#
# There are two ways to add to a spec intead of replacing it. One is to
# use +, which appends. But we need -lc_placeholder to come before -lc.
# The usual trick for that (documented in the GCC manual) is
# %rename lib old_lib
# *lib: -lc_placeholder %(old_lib)
# but GCC gets mad if old_lib already exists, and contrary to the
# documentation you cannot delete a spec, and if you set -specs in both
# CFLAGS and LDFLAGS, then this spec file runs twice if you build a
# program in one command with $(CC) $(CFLAGS) $(LDFLAGS), which autoconf
# does for test programs, causing it to fail. So, instead take advantage
# of %(mflib), an unused variable in the built-in specs in a spot we
# like (from the old "Mudflap" precursor to ASan, which was removed from
# GCC over a decade ago but they left this variable in the specs). Just
# in case anyone else had the same clever idea, we append to it, but we
# expect it to be empty. (Everything we add is idempotent, just wasteful
# to run twice.)
*cpp:
+ -isystem %:getenv(antiquator /)

*mflib:
+ -L %:getenv(antiquator /) \
--push-state --as-needed \
-lantiquator_helpers \
-lanl_placeholder \
-lc_placeholder \
-ldl_placeholder \
-lm_placeholder \
-lpthread_placeholder \
-lresolv_placeholder \
-lrt_placeholder \
-lutil_placeholder \
--pop-state

*post_link: +
%:getenv(antiquator /wrap-linker) -fuse-ld=true %{o*}
25 changes: 25 additions & 0 deletions cpython-unix/antiquator/libc_start_main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include <stdio.h>

extern int __libc_csu_init(int argc, char **argv, char **envp);

#define LIBC_START_MAIN_ARGS \
int (*main) (int, char **, char **), \
int argc, char **argv, \
__typeof (main) init, \
void (*fini) (void), \
void (*rtld_fini) (void), void *stack_end

extern int real_libc_start_main(LIBC_START_MAIN_ARGS);

// The static linker needs to find this under the name
// __libc_start_main, so that crt1.o calls this one instead of the real
// one in libc. But after we rename real_libc_start_main with patchelf
// to __libc_start_main, the dynamic linker needs to _not_ find this one
// and instead find the real one. To accomplish this, we give it a
// non-default symbol version that does not match the symbol version
// that we actually want.
__attribute__((symver("__libc_start_main@ANTIQUATOR_SHIM")))
int __libc_start_main(LIBC_START_MAIN_ARGS) {
return real_libc_start_main(main, argc, argv, __libc_csu_init, fini, rtld_fini, stack_end);
}

Loading
Loading