feat: use PIC code model for shared libraries, fix shared library bugs
This commit is contained in:
+13
-5
@@ -71,6 +71,13 @@ namespace Hal {
|
|||||||
return frame->CS;
|
return frame->CS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static System::PanicFrame* GetExceptionRegs(uint8_t vector, System::PanicFrame* frame) {
|
||||||
|
if (ExceptionHasErrorCode(vector)) {
|
||||||
|
return (System::PanicFrame*)((uint8_t*)frame + sizeof(uint64_t));
|
||||||
|
}
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
template<size_t i>
|
template<size_t i>
|
||||||
__attribute__((interrupt)) void ExceptionHandler(System::PanicFrame* frame)
|
__attribute__((interrupt)) void ExceptionHandler(System::PanicFrame* frame)
|
||||||
{
|
{
|
||||||
@@ -85,6 +92,7 @@ namespace Hal {
|
|||||||
// instead of panicking the entire system.
|
// instead of panicking the entire system.
|
||||||
if (fromUser && Sched::GetCurrentPid() >= 0) {
|
if (fromUser && Sched::GetCurrentPid() >= 0) {
|
||||||
auto* proc = Sched::GetCurrentProcessPtr();
|
auto* proc = Sched::GetCurrentProcessPtr();
|
||||||
|
auto* regs = GetExceptionRegs(i, frame);
|
||||||
Kt::KernelLogStream(Kt::ERROR, "Exception")
|
Kt::KernelLogStream(Kt::ERROR, "Exception")
|
||||||
<< ExceptionStrings[i] << " in process \""
|
<< ExceptionStrings[i] << " in process \""
|
||||||
<< proc->name << "\" (pid " << proc->pid
|
<< proc->name << "\" (pid " << proc->pid
|
||||||
@@ -99,11 +107,11 @@ namespace Hal {
|
|||||||
rep.exceptionVector = i;
|
rep.exceptionVector = i;
|
||||||
for (int j = 0; j < 32 && ExceptionStrings[i][j]; j++) rep.exceptionName[j] = ExceptionStrings[i][j];
|
for (int j = 0; j < 32 && ExceptionStrings[i][j]; j++) rep.exceptionName[j] = ExceptionStrings[i][j];
|
||||||
rep.exceptionName[31] = '\0';
|
rep.exceptionName[31] = '\0';
|
||||||
rep.instructionPointer = frame->IP;
|
rep.instructionPointer = regs->IP;
|
||||||
rep.codeSegment = frame->CS;
|
rep.codeSegment = regs->CS;
|
||||||
rep.flags = frame->Flags;
|
rep.flags = regs->Flags;
|
||||||
rep.stackPointer = frame->SP;
|
rep.stackPointer = regs->SP;
|
||||||
rep.stackSegment = frame->SS;
|
rep.stackSegment = regs->SS;
|
||||||
|
|
||||||
if (i == 0x0E) {
|
if (i == 0x0E) {
|
||||||
// Page fault: read CR2 for faulting address
|
// Page fault: read CR2 for faulting address
|
||||||
|
|||||||
@@ -268,10 +268,11 @@ namespace Sched {
|
|||||||
uint64_t copyEnd = (pageEnd < targetSegFileEnd) ? pageEnd : targetSegFileEnd;
|
uint64_t copyEnd = (pageEnd < targetSegFileEnd) ? pageEnd : targetSegFileEnd;
|
||||||
|
|
||||||
if (copyStart < copyEnd) {
|
if (copyStart < copyEnd) {
|
||||||
// Source: file data at (copyStart - targetSegStart) offset from p_offset
|
// Source stays segment-relative, but the destination must be page-relative.
|
||||||
|
// Using a segment-relative destination offset leaves page 2+ zero-filled and
|
||||||
|
// writes past the newly allocated page in the kernel mapping.
|
||||||
uint64_t srcOffset = phdr->p_offset + (copyStart - targetSegStart);
|
uint64_t srcOffset = phdr->p_offset + (copyStart - targetSegStart);
|
||||||
// Dest: page at (copyStart - targetSegStart) offset, then adjusted for this page
|
uint64_t pageDataOffset = copyStart - pageStart;
|
||||||
uint64_t pageDataOffset = copyStart - targetSegStart;
|
|
||||||
uint64_t copySize = copyEnd - copyStart;
|
uint64_t copySize = copyEnd - copyStart;
|
||||||
|
|
||||||
uint8_t* dst = (uint8_t*)Memory::HHDM(physAddr) + pageDataOffset;
|
uint8_t* dst = (uint8_t*)Memory::HHDM(physAddr) + pageDataOffset;
|
||||||
|
|||||||
@@ -281,8 +281,8 @@ dialogs: bearssl libc tls
|
|||||||
crashpad: libc
|
crashpad: libc
|
||||||
$(MAKE) -C src/crashpad
|
$(MAKE) -C src/crashpad
|
||||||
|
|
||||||
# Build test_dl (dynamic loading test app, depends on libloader).
|
# Build test_dl (dynamic loading test app, depends on libloader and shared libs).
|
||||||
test_dl: libloader libs
|
test_dl: libloader libs libhello
|
||||||
$(MAKE) -C src/test_dl
|
$(MAKE) -C src/test_dl
|
||||||
|
|
||||||
# Install app bundles (manifests, icons, data files) into bin/apps/<name>/.
|
# Install app bundles (manifests, icons, data files) into bin/apps/<name>/.
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ NM := $(TOOLCHAIN_PREFIX)nm
|
|||||||
STRIP := $(TOOLCHAIN_PREFIX)strip
|
STRIP := $(TOOLCHAIN_PREFIX)strip
|
||||||
|
|
||||||
# Compiler flags: freestanding, no stdlib
|
# Compiler flags: freestanding, no stdlib
|
||||||
|
# Build as PIE so library-internal data references remain valid after the
|
||||||
|
# kernel maps the image into a per-process library slot.
|
||||||
override CXXFLAGS := \
|
override CXXFLAGS := \
|
||||||
-std=gnu++20 \
|
-std=gnu++20 \
|
||||||
-g -O2 -pipe \
|
-g -O2 -pipe \
|
||||||
@@ -20,7 +22,7 @@ override CXXFLAGS := \
|
|||||||
-ffreestanding \
|
-ffreestanding \
|
||||||
-fno-stack-protector \
|
-fno-stack-protector \
|
||||||
-fno-stack-check \
|
-fno-stack-check \
|
||||||
-fno-PIC \
|
-fPIE \
|
||||||
-fno-rtti \
|
-fno-rtti \
|
||||||
-fno-exceptions \
|
-fno-exceptions \
|
||||||
-ffunction-sections \
|
-ffunction-sections \
|
||||||
|
|||||||
@@ -8,18 +8,47 @@
|
|||||||
#include <montauk/syscall.h>
|
#include <montauk/syscall.h>
|
||||||
#include <gui/truetype.hpp>
|
#include <gui/truetype.hpp>
|
||||||
|
|
||||||
// Exported demo function - creates a window and renders until closed
|
// Heap allocation test - allocates, writes, reads, frees
|
||||||
|
// Returns 0 on success, -1 on failure
|
||||||
|
extern "C" int hello_malloc_test() {
|
||||||
|
// Test 1: Allocate 256 bytes
|
||||||
|
void* buf = montauk::malloc(256);
|
||||||
|
if (!buf) {
|
||||||
|
montauk::print(" [libhello] malloc(256) failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test 2: Write a pattern and verify it
|
||||||
|
uint8_t* bytes = (uint8_t*)buf;
|
||||||
|
for (int i = 0; i < 256; i++) {
|
||||||
|
bytes[i] = (uint8_t)(i & 0xFF);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 256; i++) {
|
||||||
|
if (bytes[i] != (uint8_t)(i & 0xFF)) {
|
||||||
|
montauk::print(" [libhello] read verification failed\n");
|
||||||
|
montauk::mfree(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
montauk::mfree(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" int hello_run() {
|
extern "C" int hello_run() {
|
||||||
// Create window
|
// Create window
|
||||||
|
static constexpr int kInitialWidth = 320;
|
||||||
|
static constexpr int kInitialHeight = 200;
|
||||||
|
static constexpr uint32_t kBackgroundColor = 0xFFFFFFFF;
|
||||||
Montauk::WinCreateResult wres;
|
Montauk::WinCreateResult wres;
|
||||||
if (montauk::win_create("libhello Demo", 320, 200, &wres) < 0 || wres.id < 0) {
|
if (montauk::win_create("libhello Demo", kInitialWidth, kInitialHeight, &wres) < 0 || wres.id < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int winId = wres.id;
|
int winId = wres.id;
|
||||||
uint32_t* pixels = (uint32_t*)(uintptr_t)wres.pixelVa;
|
uint32_t* pixels = (uint32_t*)(uintptr_t)wres.pixelVa;
|
||||||
int width = 200;
|
int width = kInitialWidth;
|
||||||
int height = 320;
|
int height = kInitialHeight;
|
||||||
|
|
||||||
gui::TrueTypeFont* font = (gui::TrueTypeFont*)montauk::malloc(sizeof(gui::TrueTypeFont));
|
gui::TrueTypeFont* font = (gui::TrueTypeFont*)montauk::malloc(sizeof(gui::TrueTypeFont));
|
||||||
if (!font) {
|
if (!font) {
|
||||||
@@ -36,16 +65,15 @@ extern "C" int hello_run() {
|
|||||||
// Simple render - fill with a color pattern
|
// Simple render - fill with a color pattern
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
// Dark blue background
|
pixels[y * width + x] = kBackgroundColor;
|
||||||
pixels[y * width + x] = 0xFF1a1a2e;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render text using TrueType
|
// Render text using TrueType
|
||||||
gui::Color text_color;
|
gui::Color text_color;
|
||||||
text_color.r = 0xF5;
|
text_color.r = 0x11;
|
||||||
text_color.g = 0xF5;
|
text_color.g = 0x11;
|
||||||
text_color.b = 0xF5;
|
text_color.b = 0x11;
|
||||||
text_color.a = 255;
|
text_color.a = 255;
|
||||||
font->draw_to_buffer(pixels, width, height, 20, 20, "Hello from libhello!", text_color, 16);
|
font->draw_to_buffer(pixels, width, height, 20, 20, "Hello from libhello!", text_color, 16);
|
||||||
|
|
||||||
@@ -76,7 +104,7 @@ extern "C" int hello_run() {
|
|||||||
// Re-render on resize
|
// Re-render on resize
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
pixels[y * width + x] = 0xFF1a1a2e;
|
pixels[y * width + x] = kBackgroundColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
font->draw_to_buffer(pixels, width, height, 20, 20, "Hello from libhello!", text_color, 16);
|
font->draw_to_buffer(pixels, width, height, 20, 20, "Hello from libhello!", text_color, 16);
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -11,6 +11,8 @@ NM := $(TOOLCHAIN_PREFIX)nm
|
|||||||
STRIP := $(TOOLCHAIN_PREFIX)strip
|
STRIP := $(TOOLCHAIN_PREFIX)strip
|
||||||
|
|
||||||
# Compiler flags: freestanding, no stdlib
|
# Compiler flags: freestanding, no stdlib
|
||||||
|
# Build as PIE so library code remains valid when loaded into a slot-specific
|
||||||
|
# base address by the kernel loader.
|
||||||
override CXXFLAGS := \
|
override CXXFLAGS := \
|
||||||
-std=gnu++20 \
|
-std=gnu++20 \
|
||||||
-g -O2 -pipe \
|
-g -O2 -pipe \
|
||||||
@@ -20,7 +22,7 @@ override CXXFLAGS := \
|
|||||||
-ffreestanding \
|
-ffreestanding \
|
||||||
-fno-stack-protector \
|
-fno-stack-protector \
|
||||||
-fno-stack-check \
|
-fno-stack-check \
|
||||||
-fno-PIC \
|
-fPIE \
|
||||||
-fno-rtti \
|
-fno-rtti \
|
||||||
-fno-exceptions \
|
-fno-exceptions \
|
||||||
-ffunction-sections \
|
-ffunction-sections \
|
||||||
@@ -55,7 +57,7 @@ LIBSRC := src/libmath.cpp
|
|||||||
|
|
||||||
all: $(OUTDIR)/$(LIBNAME).lib $(OUTDIR)/$(LIBNAME).lib.sym
|
all: $(OUTDIR)/$(LIBNAME).lib $(OUTDIR)/$(LIBNAME).lib.sym
|
||||||
|
|
||||||
$(OUTDIR)/$(LIBNAME).lib: $(LIBSRC)
|
$(OUTDIR)/$(LIBNAME).lib: $(LIBSRC) Makefile
|
||||||
@mkdir -p $(OUTDIR)
|
@mkdir -p $(OUTDIR)
|
||||||
$(CXX) $(CXXFLAGS) -c $(LIBSRC) -o src/libmath.o
|
$(CXX) $(CXXFLAGS) -c $(LIBSRC) -o src/libmath.o
|
||||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) src/libmath.o -o $@
|
$(CXX) $(CXXFLAGS) $(LDFLAGS) src/libmath.o -o $@
|
||||||
|
|||||||
Binary file not shown.
@@ -100,7 +100,26 @@ extern "C" void _start() {
|
|||||||
// Debug: print hello_run address
|
// Debug: print hello_run address
|
||||||
montauk::print(" DEBUG: hello_run @ ");
|
montauk::print(" DEBUG: hello_run @ ");
|
||||||
print_hex((uint64_t)hello_run);
|
print_hex((uint64_t)hello_run);
|
||||||
montauk::print("\n");
|
montauk::print("\n\n");
|
||||||
|
|
||||||
|
// Test heap allocations in the shared library
|
||||||
|
montauk::print("Testing heap allocations in libhello...\n");
|
||||||
|
typedef int (*malloc_test_t)(void);
|
||||||
|
malloc_test_t malloc_test = (malloc_test_t)libloader::dlsym(hellolib, "hello_malloc_test");
|
||||||
|
if (!malloc_test) {
|
||||||
|
montauk::print("ERROR: Failed to resolve hello_malloc_test\n");
|
||||||
|
libloader::dlclose(hellolib);
|
||||||
|
montauk::exit(1);
|
||||||
|
}
|
||||||
|
montauk::print(" hello_malloc_test: OK\n");
|
||||||
|
|
||||||
|
int malloc_result = malloc_test();
|
||||||
|
if (malloc_result != 0) {
|
||||||
|
montauk::print("ERROR: heap allocation test in libhello failed\n");
|
||||||
|
libloader::dlclose(hellolib);
|
||||||
|
montauk::exit(1);
|
||||||
|
}
|
||||||
|
montauk::print(" heap allocation test: PASSED\n\n");
|
||||||
|
|
||||||
// Run the GUI demo (this creates a window and event loop)
|
// Run the GUI demo (this creates a window and event loop)
|
||||||
montauk::print("Running GUI demo...\n");
|
montauk::print("Running GUI demo...\n");
|
||||||
|
|||||||
Reference in New Issue
Block a user