summaryrefslogtreecommitdiffhomepage
path: root/src/CompilerKit
diff options
context:
space:
mode:
Diffstat (limited to 'src/CompilerKit')
-rw-r--r--src/CompilerKit/src/Compilers/NectarCompiler+AMD64.cc16
-rw-r--r--src/CompilerKit/src/Linkers/DynamicLinker64+MachO.cc160
2 files changed, 148 insertions, 28 deletions
diff --git a/src/CompilerKit/src/Compilers/NectarCompiler+AMD64.cc b/src/CompilerKit/src/Compilers/NectarCompiler+AMD64.cc
index ff1d136..9dbb4f6 100644
--- a/src/CompilerKit/src/Compilers/NectarCompiler+AMD64.cc
+++ b/src/CompilerKit/src/Compilers/NectarCompiler+AMD64.cc
@@ -355,10 +355,18 @@ CompilerKit::SyntaxLeafList::SyntaxLeaf CompilerFrontendNectarAMD64::Compile(
left = std::move(tmp);
syntax_tree.fUserValue +=
- "mov rdi, " + (isnumber(left[0]) ? left : (nectar_get_variable_ref(left).empty() ? left : nectar_get_variable_ref(left))) + "\n";
-
- syntax_tree.fUserValue +=
- "mov rsi, " + (isnumber(right[0]) ? right : (nectar_get_variable_ref(right).empty() ? right : nectar_get_variable_ref(right))) + "\n";
+ "mov rdi, " +
+ (isnumber(left[0])
+ ? left
+ : (nectar_get_variable_ref(left).empty() ? left : nectar_get_variable_ref(left))) +
+ "\n";
+
+ syntax_tree.fUserValue += "mov rsi, " +
+ (isnumber(right[0]) ? right
+ : (nectar_get_variable_ref(right).empty()
+ ? right
+ : nectar_get_variable_ref(right))) +
+ "\n";
syntax_tree.fUserValue += "cmp rdi, rsi\n";
diff --git a/src/CompilerKit/src/Linkers/DynamicLinker64+MachO.cc b/src/CompilerKit/src/Linkers/DynamicLinker64+MachO.cc
index 3db2c92..9b9d8ad 100644
--- a/src/CompilerKit/src/Linkers/DynamicLinker64+MachO.cc
+++ b/src/CompilerKit/src/Linkers/DynamicLinker64+MachO.cc
@@ -346,7 +346,8 @@ NECTAR_MODULE(DynamicLinker64MachO) {
using namespace CompilerKit::MachO;
- uint32_t numCommands = 4;
+ uint32_t numCommands = 8; // __PAGEZERO, LC_BUILD_VERSION, __TEXT, __LINKEDIT, LC_LOAD_DYLINKER,
+ // LC_UUID, LC_SYMTAB, LC_DYSYMTAB
if (!kIsDylib) {
numCommands += 1; // LC_MAIN
@@ -355,16 +356,23 @@ NECTAR_MODULE(DynamicLinker64MachO) {
uint32_t dataSegCmdSize =
kDataBytes.size() > 0 ? sizeof(segment_command_64) + sizeof(section_64) : 0;
- if (dataSegCmdSize < 1) --numCommands; // No __DATA segment
+ if (dataSegCmdSize > 0) ++numCommands; // __DATA segment
- uint32_t sizeOfCmds = 0;
- uint32_t headerSize = sizeof(mach_header_64);
- uint32_t pageZeroSize = sizeof(segment_command_64);
- uint32_t textSegCmdSize = sizeof(segment_command_64) + sizeof(section_64);
- uint32_t buildCmdSize = sizeof(build_version_command);
- uint32_t mainCmdSize = sizeof(entry_point_command);
+ uint32_t sizeOfCmds = 0;
+ uint32_t headerSize = sizeof(mach_header_64);
+ uint32_t pageZeroSize = sizeof(segment_command_64);
+ uint32_t textSegCmdSize = sizeof(segment_command_64) + sizeof(section_64);
+ uint32_t buildCmdSize = sizeof(build_version_command);
+ uint32_t mainCmdSize = sizeof(entry_point_command);
+ uint32_t uuidCmdSize = sizeof(uuid_command);
+ uint32_t symtabCmdSize = sizeof(symtab_command);
+ uint32_t dysymtabCmdSize = sizeof(dysymtab_command);
+ uint32_t linkeditCmdSize = sizeof(segment_command_64); // No sections
+ uint32_t dylinkerCmdSize =
+ (sizeof(dylinker_command) + 13 + 1 + 7) & ~7; // "/usr/lib/dyld" + padding to 8-byte align
- sizeOfCmds = pageZeroSize + textSegCmdSize + dataSegCmdSize + buildCmdSize;
+ sizeOfCmds = pageZeroSize + textSegCmdSize + dataSegCmdSize + buildCmdSize + uuidCmdSize +
+ symtabCmdSize + dysymtabCmdSize + linkeditCmdSize + dylinkerCmdSize;
if (!kIsDylib) sizeOfCmds += mainCmdSize;
@@ -372,14 +380,21 @@ NECTAR_MODULE(DynamicLinker64MachO) {
uint64_t textFileOffset = AlignToPage(headerAndCmdsSize);
uint64_t textVMAddr = kDefaultBaseAddress;
uint64_t textSegmentSize = AlignToPage(textSize > 0 ? textSize : kPageSize);
+ uint64_t textVMSize = textFileOffset + textSegmentSize; // __TEXT includes header
uint64_t dataFileOffset = textFileOffset + textSegmentSize;
- uint64_t dataVMAddr = textVMAddr + textSegmentSize;
- uint64_t dataSegmentSize = AlignToPage(dataSize > 0 ? dataSize : kPageSize);
-
- // Symbol table comes after data segment
- uint64_t symtabFileOffset = dataFileOffset + dataSegmentSize;
+ uint64_t dataVMAddr = textVMAddr + textVMSize;
+ uint64_t dataSegmentSize = dataSize > 0 ? AlignToPage(dataSize) : 0; // 0 if no data
+
+ // __LINKEDIT segment comes after data segment (or __TEXT if no data)
+ uint64_t linkeditFileOffset =
+ dataSegmentSize > 0 ? dataFileOffset + dataSegmentSize : textFileOffset + textSegmentSize;
+ uint64_t linkeditVMAddr =
+ dataSegmentSize > 0 ? dataVMAddr + dataSegmentSize : textVMAddr + textVMSize;
+ uint64_t symtabFileOffset = linkeditFileOffset;
uint64_t strtabFileOffset = symtabFileOffset + (kSymbolTable.size() * sizeof(nlist_64));
+ uint64_t linkeditFileSize = (kSymbolTable.size() * sizeof(nlist_64)) + kStringTable.size();
+ uint64_t linkeditVMSize = AlignToPage(linkeditFileSize > 0 ? linkeditFileSize : 1);
// Write Mach-O header
mach_header_64 header{};
@@ -390,7 +405,7 @@ NECTAR_MODULE(DynamicLinker64MachO) {
header.filetype = kIsDylib ? MH_DYLIB : MH_EXECUTE;
header.ncmds = numCommands;
header.sizeofcmds = sizeOfCmds;
- header.flags = MH_PIE;
+ header.flags = MH_NOUNDEFS | MH_DYLDLINK | MH_TWOLEVEL | MH_PIE;
header.reserved = 0;
output_fc.write(reinterpret_cast<const char*>(&header), sizeof(header));
@@ -404,7 +419,7 @@ NECTAR_MODULE(DynamicLinker64MachO) {
pageZeroSegment.cmdsize = sizeof(segment_command_64);
CopySegmentName(pageZeroSegment.segname, kSegmentPageZero);
pageZeroSegment.vmaddr = 0;
- pageZeroSegment.vmsize = 0x100000000ULL;
+ pageZeroSegment.vmsize = 0x100000000;
pageZeroSegment.fileoff = 0;
pageZeroSegment.filesize = 0;
pageZeroSegment.maxprot = 0;
@@ -415,7 +430,7 @@ NECTAR_MODULE(DynamicLinker64MachO) {
output_fc.write(reinterpret_cast<const char*>(&pageZeroSegment), sizeof(pageZeroSegment));
build_version_command build = {.cmd = LC_BUILD_VERSION,
- .cmdsize = sizeof(struct build_version_command),
+ .cmdsize = sizeof(build_version_command),
.platform = PLATFORM_MACOS,
.minos = (11 << 16), // macOS 11.0
.sdk = (11 << 16), // macOS 11.0
@@ -430,12 +445,13 @@ NECTAR_MODULE(DynamicLinker64MachO) {
// Write __TEXT segment command
segment_command_64 textSegment{};
textSegment.cmd = LC_SEGMENT_64;
- textSegment.cmdsize = textSegCmdSize;
+ textSegment.cmdsize = sizeof(segment_command_64) + sizeof(section_64); // 1 section
CopySegmentName(textSegment.segname, kSegmentText);
- textSegment.vmaddr = textVMAddr;
- textSegment.vmsize = textSegmentSize;
- textSegment.fileoff = textFileOffset;
- textSegment.filesize = kPageSize;
+ textSegment.vmaddr = textVMAddr;
+ textSegment.vmsize = textVMSize; // Header + code (page-aligned)
+ textSegment.fileoff = 0; // Must include Mach-O header
+ textSegment.filesize =
+ dataSegmentSize > 0 ? dataFileOffset : linkeditFileOffset; // Extend to next segment
textSegment.maxprot = VM_PROT_READ | VM_PROT_EXECUTE;
textSegment.initprot = VM_PROT_READ | VM_PROT_EXECUTE;
textSegment.nsects = 1;
@@ -447,7 +463,7 @@ NECTAR_MODULE(DynamicLinker64MachO) {
section_64 textSection{};
CopySegmentName(textSection.sectname, kSectionText);
CopySegmentName(textSection.segname, kSegmentText);
- textSection.addr = textVMAddr;
+ textSection.addr = textVMAddr + textFileOffset; // Section is at offset within segment
textSection.size = textSize;
textSection.offset = static_cast<uint32_t>(textFileOffset);
textSection.align = kSectionAlign;
@@ -468,7 +484,7 @@ NECTAR_MODULE(DynamicLinker64MachO) {
// Write __DATA segment command
segment_command_64 dataSegment{};
dataSegment.cmd = LC_SEGMENT_64;
- dataSegment.cmdsize = dataSegCmdSize;
+ dataSegment.cmdsize = sizeof(segment_command_64) + sizeof(section_64); // 1 section
CopySegmentName(dataSegment.segname, kSegmentData);
dataSegment.vmaddr = dataVMAddr;
dataSegment.vmsize = dataSegmentSize;
@@ -505,6 +521,43 @@ NECTAR_MODULE(DynamicLinker64MachO) {
kConsoleOut << " __data section, size: " << dataSize << " bytes\n";
}
+ // Write __LINKEDIT segment command (contains symbol/string tables)
+ segment_command_64 linkeditSegment{};
+ linkeditSegment.cmd = LC_SEGMENT_64;
+ linkeditSegment.cmdsize = sizeof(segment_command_64); // No sections
+ CopySegmentName(linkeditSegment.segname, "__LINKEDIT");
+ linkeditSegment.vmaddr = linkeditVMAddr;
+ linkeditSegment.vmsize = linkeditVMSize;
+ linkeditSegment.fileoff = linkeditFileOffset;
+ linkeditSegment.filesize = linkeditFileSize;
+ linkeditSegment.maxprot = VM_PROT_READ;
+ linkeditSegment.initprot = VM_PROT_READ;
+ linkeditSegment.nsects = 0;
+ linkeditSegment.flags = 0;
+
+ output_fc.write(reinterpret_cast<const char*>(&linkeditSegment), sizeof(linkeditSegment));
+
+ if (kVerbose) {
+ kConsoleOut << "Wrote __LINKEDIT segment, vmaddr: 0x" << std::hex << linkeditVMAddr << std::dec
+ << ", fileoff: " << linkeditFileOffset << ", filesize: " << linkeditFileSize
+ << "\n";
+ }
+
+ // Write LC_LOAD_DYLINKER command
+ const char* dyldPath = "/usr/lib/dyld";
+ std::vector<char> dylinkerCmd(dylinkerCmdSize, 0);
+ dylinker_command* dylinker = reinterpret_cast<dylinker_command*>(dylinkerCmd.data());
+ dylinker->cmd = LC_LOAD_DYLINKER;
+ dylinker->cmdsize = dylinkerCmdSize;
+ dylinker->name.offset = sizeof(dylinker_command);
+ std::memcpy(dylinkerCmd.data() + sizeof(dylinker_command), dyldPath, strlen(dyldPath) + 1);
+
+ output_fc.write(dylinkerCmd.data(), dylinkerCmd.size());
+
+ if (kVerbose) {
+ kConsoleOut << "Wrote LC_LOAD_DYLINKER: " << dyldPath << "\n";
+ }
+
// Write LC_MAIN entry point command (executables only)
if (!kIsDylib) {
entryCommand.cmd = LC_MAIN;
@@ -520,6 +573,65 @@ NECTAR_MODULE(DynamicLinker64MachO) {
}
}
+ // Write LC_UUID command
+ uuid_command uuidCmd{};
+ uuidCmd.cmd = LC_UUID;
+ uuidCmd.cmdsize = sizeof(uuid_command);
+
+ // Generate a random UUID (version 4)
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ uuids::uuid_random_generator uuidGen(gen);
+ uuids::uuid generatedUuid = uuidGen();
+ auto uuidBytes = generatedUuid.as_bytes();
+ std::memcpy(uuidCmd.uuid, uuidBytes.data(), 16);
+
+ output_fc.write(reinterpret_cast<const char*>(&uuidCmd), sizeof(uuidCmd));
+
+ if (kVerbose) {
+ kConsoleOut << "Wrote LC_UUID\n";
+ }
+
+ // Write LC_SYMTAB command
+ symtab_command symtabCmd{};
+ symtabCmd.cmd = LC_SYMTAB;
+ symtabCmd.cmdsize = sizeof(symtab_command);
+ symtabCmd.symoff = static_cast<uint32_t>(symtabFileOffset);
+ symtabCmd.nsyms = static_cast<uint32_t>(kSymbolTable.size());
+ symtabCmd.stroff = static_cast<uint32_t>(strtabFileOffset);
+ symtabCmd.strsize = static_cast<uint32_t>(kStringTable.size());
+
+ output_fc.write(reinterpret_cast<const char*>(&symtabCmd), sizeof(symtabCmd));
+
+ if (kVerbose) {
+ kConsoleOut << "Wrote LC_SYMTAB, nsyms: " << symtabCmd.nsyms
+ << ", strsize: " << symtabCmd.strsize << "\n";
+ }
+
+ // Write LC_DYSYMTAB command
+ dysymtab_command dysymtabCmd{};
+ std::memset(&dysymtabCmd, 0, sizeof(dysymtabCmd));
+ dysymtabCmd.cmd = LC_DYSYMTAB;
+ dysymtabCmd.cmdsize = sizeof(dysymtab_command);
+
+ // All symbols are local for now
+ dysymtabCmd.ilocalsym = 0;
+ dysymtabCmd.nlocalsym = static_cast<uint32_t>(kSymbolTable.size());
+
+ // External symbols start after locals
+ dysymtabCmd.iextdefsym = static_cast<uint32_t>(kSymbolTable.size());
+ dysymtabCmd.nextdefsym = 0;
+
+ // Undefined symbols
+ dysymtabCmd.iundefsym = static_cast<uint32_t>(kSymbolTable.size());
+ dysymtabCmd.nundefsym = 0;
+
+ output_fc.write(reinterpret_cast<const char*>(&dysymtabCmd), sizeof(dysymtabCmd));
+
+ if (kVerbose) {
+ kConsoleOut << "Wrote LC_DYSYMTAB\n";
+ }
+
// Pad to text section offset
uint64_t currentPos = output_fc.tellp();
uint64_t padding = textFileOffset - currentPos;