11#include " loader.h"
22
3- #if defined(__linux__)
4- #define _GNU_SOURCE
5- #endif
6-
73#include < stdio.h>
84#include < stdlib.h>
95#include < string.h>
6+ #include < string>
7+ #include < stdexcept>
108
119#if defined(_WIN32) || defined(__CYGWIN__)
1210#include < windows.h>
1311#else
1412#include < dlfcn.h>
1513#include < unistd.h>
16- #endif
17-
18- #if defined(__linux__)
19- #include < sys/mman.h>
20- #endif
21-
22- #include < string>
23- #include < stdexcept>
24-
25- #if defined(_WIN32) || defined(__CYGWIN__)
26- #include < windows.h>
27- #elif defined(__linux__) || defined(__APPLE__)
2814#include < unistd.h>
2915#include < fcntl.h>
3016#include < cerrno>
3117#endif
3218
3319#if defined(__linux__)
3420#include < sys/mman.h>
21+ #include < sys/stat.h>
22+ #include < elf.h>
23+ #include < iostream>
24+ #include < fstream>
3525#endif
3626
3727std::string ModInstance::GenerateTempFile () {
@@ -50,27 +40,18 @@ std::string ModInstance::GenerateTempFile() {
5040
5141 return std::string (tempFileName);
5242
53- #elif defined(__linux__)
54- int fd = memfd_create (" virtual_mod_lib" , 0 );
55- if (fd == -1 ) {
56- throw std::runtime_error (" Failed to create memfd: " + std::to_string (errno));
57- }
58-
59- // IMPORTANT: We deliberately DO NOT close(fd) here!
60- // A memfd only exists in RAM as long as an open file descriptor points to it.
61- // If we closed it, the file would instantly vanish and the path would become invalid.
62- char path[256 ];
63- snprintf (path, sizeof (path), " /proc/self/fd/%d" , fd);
64- return std::string (path);
65-
66- #elif defined(__APPLE__)
43+ #elif defined(__APPLE__) || defined(__linux__)
6744 char path_template[] = " /tmp/mod_lib_XXXXXX" ;
6845
6946 int fd = mkstemp (path_template);
7047 if (fd == -1 ) {
7148 throw std::runtime_error (" Failed to create temporary file: " + std::to_string (errno));
7249 }
7350
51+ #ifdef __linux__
52+ fchmod (fd, 0755 );
53+ #endif
54+
7455 // mkstemp creates a physical file on the hard drive.
7556 // We can safely close the FD now; the file will remain on disk for you to open later.
7657 close (fd);
@@ -81,6 +62,64 @@ std::string ModInstance::GenerateTempFile() {
8162#endif
8263}
8364
65+ #ifdef __linux__
66+ void FixELFHeader (const std::string& path) {
67+ // 1. Read the file into a buffer
68+ std::ifstream in (path, std::ios::binary | std::ios::ate);
69+ if (!in.is_open ()) return ;
70+
71+ std::streamsize size = in.tellg ();
72+ in.seekg (0 , std::ios::beg);
73+
74+ std::vector<uint8_t > buffer (size);
75+ if (!in.read (reinterpret_cast <char *>(buffer.data ()), size)) return ;
76+ in.close ();
77+
78+ if (buffer.size () < sizeof (Elf64_Ehdr)) return ;
79+
80+ // 2. ELF Surgery
81+ Elf64_Ehdr* header = reinterpret_cast <Elf64_Ehdr*>(buffer.data ());
82+
83+ if (header->e_ident [EI_CLASS ] == ELFCLASS64 ) {
84+ Elf64_Phdr* phdr = reinterpret_cast <Elf64_Phdr*>(buffer.data () + header->e_phoff );
85+
86+ bool patched = false ;
87+ for (int i = 0 ; i < header->e_phnum ; i++) {
88+ // Target PT_NOTE (0x4) OR PT_GNU_EH_FRAME (0x6474e550)
89+ // TCC doesn't give us a NOTE, so we hijack the EH_FRAME header.
90+ if (phdr[i].p_type == PT_NOTE || phdr[i].p_type == 0x6474e550 ) {
91+ phdr[i].p_type = PT_GNU_STACK ; // Change to 0x6474e551
92+ phdr[i].p_flags = PF_R | PF_W ; // Set to RW (No Execute)
93+ phdr[i].p_align = 0x10 ;
94+ patched = true ;
95+ break ;
96+ }
97+ }
98+
99+ if (!patched) {
100+ // Last resort: if we can't find either, we'll try to find any
101+ // non-critical segment that isn't LOAD (1) or DYNAMIC (2).
102+ for (int i = 0 ; i < header->e_phnum ; i++) {
103+ if (phdr[i].p_type != PT_LOAD && phdr[i].p_type != PT_DYNAMIC ) {
104+ phdr[i].p_type = PT_GNU_STACK ;
105+ phdr[i].p_flags = PF_R | PF_W ;
106+ break ;
107+ }
108+ }
109+ }
110+ }
111+
112+ // 3. Write it back
113+ std::ofstream out (path, std::ios::binary | std::ios::trunc);
114+ if (!out.is_open ()) return ;
115+ out.write (reinterpret_cast <const char *>(buffer.data ()), buffer.size ());
116+ out.close ();
117+
118+ // 4. Ensure permissions are set to allow execution of the file
119+ chmod (path.c_str (), 0755 );
120+ }
121+ #endif
122+
84123void ModInstance::Init (const std::string& path) {
85124#if defined(_WIN32) || defined(__CYGWIN__)
86125 HMODULE handle = LoadLibraryA (path.c_str ());
@@ -91,15 +130,10 @@ void ModInstance::Init(const std::string& path) {
91130 } else {
92131 throw std::runtime_error (" Failed to load library: " + std::to_string (GetLastError ()));
93132 }
94- #elif defined(__linux__)
95- void * handle = dlopen (path.c_str (), RTLD_NOW );
96- if (handle) {
97- this ->mHandle = handle;
98- return ;
99- } else {
100- throw std::runtime_error (" Failed to load library: " + std::string (dlerror ()));
101- }
102- #elif defined(__APPLE__)
133+ #elif defined(__linux__) || defined(__APPLE__)
134+ #ifdef __linux__
135+ FixELFHeader (path);
136+ #endif
103137 void * handle = dlopen (path.c_str (), RTLD_NOW );
104138 if (handle) {
105139 this ->mHandle = handle;
0 commit comments