Joseph Huber 2e1c0ec629 [libc] Support global constructors and destructors on NVPTX
This patch adds the necessary hacks to support global constructors and
destructors. This is an incredibly hacky process caused by the primary
fact that Nvidia does not provide any binary tools and very little
linker support. We first had to emit references to these functions and
their priority in D149451. Then we dig them out of the module once it's
loaded to manually create the list that the linker should have made for
us. This patch also contains a few Nvidia specific hacks, but it passes
the test, albeit with a stack size warning from `ptxas` for the
callback. But this should be fine given the resource usage of a common
test.

This also adds a dependency on LLVM to the NVPTX loader, which hopefully doesn't
cause problems with our CUDA buildbot.

Depends on D149451

Reviewed By: tra

Differential Revision: https://reviews.llvm.org/D149527
2023-05-04 07:13:00 -05:00

82 lines
2.7 KiB
C++

//===-- Simple malloc and free for use with integration tests -------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <stddef.h>
#include <stdint.h>
// Integration tests rely on the following memory functions. This is because the
// compiler code generation can emit calls to them. We want to map the external
// entrypoint to the internal implementation of the function used for testing.
// This is done manually as not all targets support aliases.
namespace __llvm_libc {
int bcmp(const void *lhs, const void *rhs, size_t count);
void bzero(void *ptr, size_t count);
int memcmp(const void *lhs, const void *rhs, size_t count);
void *memcpy(void *__restrict, const void *__restrict, size_t);
void *memmove(void *dst, const void *src, size_t count);
void *memset(void *ptr, int value, size_t count);
int atexit(void (*func)(void));
} // namespace __llvm_libc
extern "C" {
int bcmp(const void *lhs, const void *rhs, size_t count) {
return __llvm_libc::bcmp(lhs, rhs, count);
}
void bzero(void *ptr, size_t count) { __llvm_libc::bzero(ptr, count); }
int memcmp(const void *lhs, const void *rhs, size_t count) {
return __llvm_libc::memcmp(lhs, rhs, count);
}
void *memcpy(void *__restrict dst, const void *__restrict src, size_t count) {
return __llvm_libc::memcpy(dst, src, count);
}
void *memmove(void *dst, const void *src, size_t count) {
return __llvm_libc::memmove(dst, src, count);
}
void *memset(void *ptr, int value, size_t count) {
return __llvm_libc::memset(ptr, value, count);
}
// This is needed if the test was compiled with '-fno-use-cxa-atexit'.
int atexit(void (*func)(void)) { return __llvm_libc::atexit(func); }
} // extern "C"
// Integration tests cannot use the SCUDO standalone allocator as SCUDO pulls
// various other parts of the libc. Since SCUDO development does not use
// LLVM libc build rules, it is very hard to keep track or pull all that SCUDO
// requires. Hence, as a work around for this problem, we use a simple allocator
// which just hands out continuous blocks from a statically allocated chunk of
// memory.
static uint8_t memory[16384];
static uint8_t *ptr = memory;
extern "C" {
void *malloc(size_t s) {
void *mem = ptr;
ptr += s;
return mem;
}
void free(void *) {}
void *realloc(void *ptr, size_t s) {
free(ptr);
return malloc(s);
}
// Integration tests are linked with -nostdlib. BFD linker expects
// __dso_handle when -nostdlib is used.
void *__dso_handle = nullptr;
} // extern "C"