From 770dde500116d72d81c002a4fa987355e07affe5 Mon Sep 17 00:00:00 2001 From: Daniel Hammer Date: Sat, 21 Mar 2026 17:35:16 +0100 Subject: [PATCH] feat: Intel GPU fixes, add tcc compiler, spreadsheet improvements, paint app, file manager improvements --- kernel/src/Drivers/Graphics/IntelGPU.cpp | 83 +- kernel/src/Drivers/Graphics/IntelGPU.hpp | 16 + programs/GNUmakefile | 23 +- programs/include/gui/desktop.hpp | 14 + programs/include/gui/svg.hpp | 74 +- programs/include/libc/montauk.h | 580 ++ programs/include/libc/unistd.h | 1 + programs/lib/libc/libc.c | 665 +- programs/lib/libc/obj/libc.o | Bin 105256 -> 186120 bytes programs/src/desktop/apps/app_filemanager.cpp | 1323 ++- programs/src/desktop/apps/app_texteditor.cpp | 378 +- programs/src/installer/actions.cpp | 12 + programs/src/mtkfetch/main.cpp | 279 + programs/src/paint/Makefile | 86 + programs/src/paint/drawing.cpp | 238 + programs/src/paint/helpers.cpp | 85 + programs/src/paint/main.cpp | 486 + programs/src/paint/manifest.toml | 8 + programs/src/paint/paint.h | 198 + programs/src/paint/render.cpp | 204 + programs/src/paint/stb_truetype_impl.cpp | 35 + programs/src/shell/exec.cpp | 90 +- programs/src/spreadsheet/edit.cpp | 56 + programs/src/spreadsheet/formula.cpp | 239 + programs/src/spreadsheet/main.cpp | 216 +- programs/src/spreadsheet/render.cpp | 101 +- programs/src/spreadsheet/spreadsheet.h | 29 + programs/src/tcc/COPYING | 504 + programs/src/tcc/Makefile | 153 + programs/src/tcc/VERSION | 1 + programs/src/tcc/coff.h | 446 + programs/src/tcc/config.h | 42 + programs/src/tcc/crt/crt1.c | 77 + programs/src/tcc/crt/crti.c | 7 + programs/src/tcc/crt/crtn.c | 7 + programs/src/tcc/dwarf.h | 1046 ++ programs/src/tcc/elf.h | 3324 ++++++ programs/src/tcc/i386-asm.c | 1757 ++++ programs/src/tcc/i386-asm.h | 490 + programs/src/tcc/i386-tok.h | 332 + programs/src/tcc/libtcc.c | 2272 +++++ programs/src/tcc/libtcc.h | 128 + programs/src/tcc/montauk_compat.h | 221 + programs/src/tcc/montauk_main.c | 229 + programs/src/tcc/setjmp.S | 56 + programs/src/tcc/stab.def | 234 + programs/src/tcc/stab.h | 17 + programs/src/tcc/tcc.c | 448 + programs/src/tcc/tcc.h | 2042 ++++ programs/src/tcc/tcc_include/float.h | 75 + programs/src/tcc/tcc_include/stdalign.h | 16 + programs/src/tcc/tcc_include/stdarg.h | 14 + programs/src/tcc/tcc_include/stdatomic.h | 171 + programs/src/tcc/tcc_include/stdbool.h | 11 + programs/src/tcc/tcc_include/stddef.h | 39 + programs/src/tcc/tcc_include/stdnoreturn.h | 7 + programs/src/tcc/tcc_include/tccdefs.h | 377 + programs/src/tcc/tcc_include/tgmath.h | 89 + programs/src/tcc/tcc_include/varargs.h | 12 + programs/src/tcc/tccasm.c | 1466 +++ programs/src/tcc/tccdbg.c | 2676 +++++ programs/src/tcc/tccelf.c | 4116 ++++++++ programs/src/tcc/tccgen.c | 8920 +++++++++++++++++ programs/src/tcc/tcclib.h | 80 + programs/src/tcc/tccpp.c | 4005 ++++++++ programs/src/tcc/tcctok.h | 430 + programs/src/tcc/tcctools.c | 651 ++ programs/src/tcc/x86_64-asm.h | 559 ++ programs/src/tcc/x86_64-gen.c | 2313 +++++ programs/src/tcc/x86_64-link.c | 410 + scripts/copy_icons.sh | 14 + scripts/install_apps.sh | 1 + 72 files changed, 45499 insertions(+), 305 deletions(-) create mode 100644 programs/include/libc/montauk.h create mode 100644 programs/src/mtkfetch/main.cpp create mode 100644 programs/src/paint/Makefile create mode 100644 programs/src/paint/drawing.cpp create mode 100644 programs/src/paint/helpers.cpp create mode 100644 programs/src/paint/main.cpp create mode 100644 programs/src/paint/manifest.toml create mode 100644 programs/src/paint/paint.h create mode 100644 programs/src/paint/render.cpp create mode 100644 programs/src/paint/stb_truetype_impl.cpp create mode 100644 programs/src/tcc/COPYING create mode 100644 programs/src/tcc/Makefile create mode 100644 programs/src/tcc/VERSION create mode 100644 programs/src/tcc/coff.h create mode 100644 programs/src/tcc/config.h create mode 100644 programs/src/tcc/crt/crt1.c create mode 100644 programs/src/tcc/crt/crti.c create mode 100644 programs/src/tcc/crt/crtn.c create mode 100644 programs/src/tcc/dwarf.h create mode 100644 programs/src/tcc/elf.h create mode 100644 programs/src/tcc/i386-asm.c create mode 100644 programs/src/tcc/i386-asm.h create mode 100644 programs/src/tcc/i386-tok.h create mode 100644 programs/src/tcc/libtcc.c create mode 100644 programs/src/tcc/libtcc.h create mode 100644 programs/src/tcc/montauk_compat.h create mode 100644 programs/src/tcc/montauk_main.c create mode 100644 programs/src/tcc/setjmp.S create mode 100644 programs/src/tcc/stab.def create mode 100644 programs/src/tcc/stab.h create mode 100644 programs/src/tcc/tcc.c create mode 100644 programs/src/tcc/tcc.h create mode 100644 programs/src/tcc/tcc_include/float.h create mode 100644 programs/src/tcc/tcc_include/stdalign.h create mode 100644 programs/src/tcc/tcc_include/stdarg.h create mode 100644 programs/src/tcc/tcc_include/stdatomic.h create mode 100644 programs/src/tcc/tcc_include/stdbool.h create mode 100644 programs/src/tcc/tcc_include/stddef.h create mode 100644 programs/src/tcc/tcc_include/stdnoreturn.h create mode 100644 programs/src/tcc/tcc_include/tccdefs.h create mode 100644 programs/src/tcc/tcc_include/tgmath.h create mode 100644 programs/src/tcc/tcc_include/varargs.h create mode 100644 programs/src/tcc/tccasm.c create mode 100644 programs/src/tcc/tccdbg.c create mode 100644 programs/src/tcc/tccelf.c create mode 100644 programs/src/tcc/tccgen.c create mode 100644 programs/src/tcc/tcclib.h create mode 100644 programs/src/tcc/tccpp.c create mode 100644 programs/src/tcc/tcctok.h create mode 100644 programs/src/tcc/tcctools.c create mode 100644 programs/src/tcc/x86_64-asm.h create mode 100644 programs/src/tcc/x86_64-gen.c create mode 100644 programs/src/tcc/x86_64-link.c diff --git a/kernel/src/Drivers/Graphics/IntelGPU.cpp b/kernel/src/Drivers/Graphics/IntelGPU.cpp index 7574b1d..881ff18 100644 --- a/kernel/src/Drivers/Graphics/IntelGPU.cpp +++ b/kernel/src/Drivers/Graphics/IntelGPU.cpp @@ -107,15 +107,36 @@ namespace Drivers::Graphics::IntelGPU { << " at PCI " << (uint64_t)found->Bus << ":" << (uint64_t)found->Device << "." << (uint64_t)found->Function; } else { - // Unknown device ID - accept generically but warn - g_gpuInfo.gen = 7; // Assume gen 7 as a safe default + // Unknown device ID - infer generation from device ID range. + // Getting this wrong is catastrophic (32-bit vs 64-bit GTT PTEs), + // so use known Intel device ID patterns. + uint16_t did = found->DeviceId; + uint8_t inferredGen; + if (did >= 0xA700 || (did >= 0x4600 && did < 0x4700) || + (did >= 0x5600 && did < 0x5700) || (did >= 0x7D00 && did < 0x7E00)) { + inferredGen = 12; // Raptor Lake, Alder Lake, DG2, Meteor Lake range + } else if ((did >= 0x8A00 && did < 0x8B00) || + (did >= 0x9A00 && did < 0x9B00)) { + inferredGen = 12; // Ice Lake / Tiger Lake range + } else if ((did >= 0x3E00 && did < 0x3F00) || + (did >= 0x5900 && did < 0x5A00) || + (did >= 0x9B00 && did < 0x9C00) || + (did >= 0x1900 && did < 0x1A00)) { + inferredGen = 9; // Skylake / Kaby Lake / Coffee Lake / Comet Lake + } else if (did >= 0x1600 && did < 0x1700) { + inferredGen = 8; // Broadwell + } else { + inferredGen = 7; // Older (Haswell and below) + } + g_gpuInfo.gen = inferredGen; g_gpuInfo.name = "Intel GPU"; KernelLogStream(WARNING, "IntelGPU") << "Unknown Intel display controller " << "(device " << base::hex << (uint64_t)found->DeviceId << ")" << " at PCI " << (uint64_t)found->Bus << ":" << (uint64_t)found->Device << "." << (uint64_t)found->Function - << " - attempting generic initialization"; + << " - inferred gen " << base::dec << (uint64_t)inferredGen + << ", attempting generic initialization"; } g_gpuGen = g_gpuInfo.gen; @@ -494,13 +515,32 @@ namespace Drivers::Graphics::IntelGPU { << " at PCI " << (uint64_t)dev.Bus << ":" << (uint64_t)dev.Device << "." << (uint64_t)dev.Function; } else { - g_gpuInfo.gen = 7; + uint16_t did = dev.DeviceId; + uint8_t inferredGen; + if (did >= 0xA700 || (did >= 0x4600 && did < 0x4700) || + (did >= 0x5600 && did < 0x5700) || (did >= 0x7D00 && did < 0x7E00)) { + inferredGen = 12; + } else if ((did >= 0x8A00 && did < 0x8B00) || + (did >= 0x9A00 && did < 0x9B00)) { + inferredGen = 12; + } else if ((did >= 0x3E00 && did < 0x3F00) || + (did >= 0x5900 && did < 0x5A00) || + (did >= 0x9B00 && did < 0x9C00) || + (did >= 0x1900 && did < 0x1A00)) { + inferredGen = 9; + } else if (did >= 0x1600 && did < 0x1700) { + inferredGen = 8; + } else { + inferredGen = 7; + } + g_gpuInfo.gen = inferredGen; g_gpuInfo.name = "Intel GPU"; KernelLogStream(WARNING, "IntelGPU") << "Unknown Intel display controller " << "(device " << base::hex << (uint64_t)dev.DeviceId << ")" << " at PCI " << (uint64_t)dev.Bus << ":" << (uint64_t)dev.Device << "." << (uint64_t)dev.Function - << " - attempting generic initialization"; + << " - inferred gen " << base::dec << (uint64_t)inferredGen + << ", attempting generic initialization"; } g_gpuGen = g_gpuInfo.gen; @@ -643,14 +683,35 @@ namespace Drivers::Graphics::IntelGPU { void Reinitialize() { if (!g_initialized || !g_mmioBase) return; - KernelLogStream(INFO, "IntelGPU") << "Reinitializing display after S3 resume"; + KernelLogStream(INFO, "IntelGPU") << "Reinitializing display after S3 resume" + << " (gen " << base::dec << (uint64_t)g_gpuGen << ")"; // 1. Re-enable PCI memory space and bus mastering. S3 resets the PCI // command register, so MMIO writes to the GPU are silently dropped // until we re-enable these bits. Pci::EnableBusMaster(g_gpuInfo.pciBus, g_gpuInfo.pciDevice, g_gpuInfo.pciFunction); - KernelLogStream(DEBUG, "IntelGPU") << "PCI memory space and bus mastering re-enabled"; + // Verify PCI memory space is accessible by reading back command register + uint16_t pciCmd = Pci::LegacyRead16(g_gpuInfo.pciBus, g_gpuInfo.pciDevice, + g_gpuInfo.pciFunction, (uint8_t)Pci::PCI_REG_COMMAND); + if (!(pciCmd & Pci::PCI_CMD_MEM_SPACE)) { + KernelLogStream(ERROR, "IntelGPU") + << "PCI memory space not enabled after restore (cmd=" + << base::hex << (uint64_t)pciCmd << ")"; + return; + } + + // Sanity-check MMIO access: read a register and verify we don't get 0xFFFFFFFF + // (which indicates the device is not responding on the PCI bus) + uint32_t testRead = ReadReg(PIPEACONF); + if (testRead == 0xFFFFFFFF) { + KernelLogStream(ERROR, "IntelGPU") + << "MMIO reads return 0xFFFFFFFF - GPU not responding"; + return; + } + + KernelLogStream(DEBUG, "IntelGPU") << "PCI memory space verified (cmd=" + << base::hex << (uint64_t)pciCmd << ")"; // 2. Disable VGA plane (firmware may have re-enabled it during POST) DisableVga(); @@ -673,6 +734,9 @@ namespace Drivers::Graphics::IntelGPU { (void)gtt32[pageCount - 1]; } + KernelLogStream(DEBUG, "IntelGPU") << "GTT reprogrammed: " << base::dec << pageCount + << " pages (" << (g_gpuGen >= 8 ? "64-bit" : "32-bit") << " PTEs)"; + // 4. Re-enable the display pipe. After S3, the pipe may be off even // though the firmware lit the backlight. Wait for it to become // active before programming the display plane. @@ -686,6 +750,11 @@ namespace Drivers::Graphics::IntelGPU { break; asm volatile("pause"); } + + if (!(ReadReg(PIPEACONF) & PIPECONF_STATE)) { + KernelLogStream(WARNING, "IntelGPU") + << "Pipe A did not become active after enable"; + } } // 5. Reprogram display plane to point at our GTT-mapped framebuffer diff --git a/kernel/src/Drivers/Graphics/IntelGPU.hpp b/kernel/src/Drivers/Graphics/IntelGPU.hpp index 16ee175..4ae0fbe 100644 --- a/kernel/src/Drivers/Graphics/IntelGPU.hpp +++ b/kernel/src/Drivers/Graphics/IntelGPU.hpp @@ -111,6 +111,22 @@ namespace Drivers::Graphics::IntelGPU { {0x4680, 12, "Alder Lake-S GT1"}, {0x4692, 12, "Alder Lake-S GT1"}, {0x46A6, 12, "Alder Lake-P GT2"}, + + // Gen 12 - Raptor Lake-P + {0xA7A0, 12, "Raptor Lake-P GT2"}, + {0xA7A1, 12, "Raptor Lake-P GT2"}, + {0xA720, 12, "Raptor Lake-P GT2"}, + {0xA721, 12, "Raptor Lake-P GT2"}, + {0xA7A8, 12, "Raptor Lake-P GT2"}, + {0xA7A9, 12, "Raptor Lake-P GT2"}, + + // Gen 12 - Raptor Lake-S + {0xA780, 12, "Raptor Lake-S GT1"}, + {0xA781, 12, "Raptor Lake-S GT1"}, + {0xA782, 12, "Raptor Lake-S GT2"}, + {0xA783, 12, "Raptor Lake-S GT2"}, + {0xA788, 12, "Raptor Lake-S GT1"}, + {0xA789, 12, "Raptor Lake-S GT1"}, }; static constexpr int SupportedDeviceCount = sizeof(SupportedDevices) / sizeof(SupportedDevices[0]); diff --git a/programs/GNUmakefile b/programs/GNUmakefile index 903a68d..c18f5e9 100644 --- a/programs/GNUmakefile +++ b/programs/GNUmakefile @@ -59,7 +59,7 @@ BINDIR := bin PROGRAMS := $(notdir $(wildcard src/*)) # Programs with custom Makefiles (built separately). -CUSTOM_BUILDS := doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet pdfviewer disks devexplorer installer volume music bluetooth desktop login shell rpgdemo +CUSTOM_BUILDS := doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet pdfviewer disks devexplorer installer volume music bluetooth desktop login shell rpgdemo paint tcc SYSTEM_PROGRAMS := $(filter-out $(CUSTOM_BUILDS),$(PROGRAMS)) # Build targets: system programs go to bin/os/, apps go to bin/apps//. @@ -81,9 +81,9 @@ CA_CERTS := $(BINDIR)/etc/ca-certificates.crt # Common shared assets (wallpapers, etc.) COMMONKEEP := $(BINDIR)/common/.keep -.PHONY: all clean doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet pdfviewer disks devexplorer installer volume music bluetooth login desktop shell rpgdemo icons fonts bearssl libc tls libjpeg install-apps +.PHONY: all clean doom fetch wiki wikipedia weather imageviewer fontpreview spreadsheet pdfviewer disks devexplorer installer volume music bluetooth login desktop shell rpgdemo paint tcc icons fonts bearssl libc tls libjpeg install-apps -all: bearssl libc libjpeg tls $(TARGETS) fetch wiki wikipedia weather imageviewer fontpreview spreadsheet pdfviewer disks devexplorer installer volume music bluetooth doom rpgdemo login desktop shell icons fonts install-apps $(MANDST) $(WWWDST) $(CA_CERTS) $(COMMONKEEP) +all: bearssl libc libjpeg tls $(TARGETS) fetch wiki wikipedia weather imageviewer fontpreview spreadsheet pdfviewer disks devexplorer installer volume music bluetooth doom rpgdemo paint tcc login desktop shell icons fonts install-apps $(MANDST) $(WWWDST) $(CA_CERTS) $(COMMONKEEP) # Build BearSSL static library (cross-compiled for freestanding x86_64). BEARSSL_INCLUDES := -isystem $(shell cd .. && pwd)/kernel/freestnd-c-hdrs/x86_64/include -isystem $(abspath include/libc) @@ -184,6 +184,10 @@ icons: fonts: ../scripts/copy_fonts.sh +# Build paint standalone GUI tool (depends on libc). +paint: libc + $(MAKE) -C src/paint + # Build RPG demo game via its own Makefile (depends on libc). rpgdemo: libc $(MAKE) -C src/rpgdemo @@ -192,8 +196,17 @@ rpgdemo: libc doom: $(MAKE) -C src/doom +# Build TCC (Tiny C Compiler) via its own Makefile (depends on libc). +tcc: libc + $(MAKE) -C src/tcc + mkdir -p $(BINDIR)/lib/tcc/include + cp -r src/tcc/tcc_include/* $(BINDIR)/lib/tcc/include/ + cp include/libc/*.h $(BINDIR)/lib/tcc/include/ + mkdir -p $(BINDIR)/lib/tcc/include/sys + cp include/libc/sys/*.h $(BINDIR)/lib/tcc/include/sys/ + # Install app bundles (manifests, icons, data files) into bin/apps//. -install-apps: doom rpgdemo spreadsheet weather wikipedia imageviewer fontpreview pdfviewer disks devexplorer installer volume music bluetooth +install-apps: doom rpgdemo paint spreadsheet weather wikipedia imageviewer fontpreview pdfviewer disks devexplorer installer volume music bluetooth ../scripts/install_apps.sh # Copy man pages into bin/man/ so mkramdisk.sh picks them up. @@ -245,4 +258,6 @@ clean: $(MAKE) -C src/volume clean $(MAKE) -C src/music clean $(MAKE) -C src/bluetooth clean + $(MAKE) -C src/paint clean $(MAKE) -C src/rpgdemo clean + $(MAKE) -C src/tcc clean diff --git a/programs/include/gui/desktop.hpp b/programs/include/gui/desktop.hpp index c37b892..7e8c733 100644 --- a/programs/include/gui/desktop.hpp +++ b/programs/include/gui/desktop.hpp @@ -95,6 +95,20 @@ struct DesktopState { SvgIcon icon_drive; SvgIcon icon_drive_lg; SvgIcon icon_delete; + SvgIcon icon_copy; + SvgIcon icon_cut; + SvgIcon icon_paste; + SvgIcon icon_rename; + SvgIcon icon_folder_new; + SvgIcon icon_home_folder; + SvgIcon icon_home_folder_lg; + SvgIcon icon_apps; + SvgIcon icon_apps_lg; + + // Special user folder icons (16x16 and 48x48) + static constexpr int SPECIAL_FOLDER_COUNT = 6; + SvgIcon icon_special_folder[SPECIAL_FOLDER_COUNT]; + SvgIcon icon_special_folder_lg[SPECIAL_FOLDER_COUNT]; SvgIcon icon_settings; SvgIcon icon_reboot; diff --git a/programs/include/gui/svg.hpp b/programs/include/gui/svg.hpp index 5b821cf..263d964 100644 --- a/programs/include/gui/svg.hpp +++ b/programs/include/gui/svg.hpp @@ -1027,6 +1027,42 @@ inline bool svg_element_has_filter(const char* elem, int elemLen) { return svg_get_attr(elem, elemLen, " filter", buf, sizeof(buf)) > 0; } +// --------------------------------------------------------------------------- +// Parse transform="scale(x)" or transform="scale(x,y)" or translate(x,y) +// Returns true if a scale was found; sx/sy are fixed-point scale factors. +// --------------------------------------------------------------------------- +inline bool svg_get_element_scale(const char* elem, int elemLen, + fixed_t* sx, fixed_t* sy) { + char buf[64]; + if (svg_get_attr(elem, elemLen, " transform", buf, sizeof(buf)) <= 0) { + *sx = int_to_fixed(1); + *sy = int_to_fixed(1); + return false; + } + // Look for "scale(" + const char* sp = buf; + while (*sp) { + if (sp[0]=='s' && sp[1]=='c' && sp[2]=='a' && sp[3]=='l' && sp[4]=='e' && sp[5]=='(') { + sp += 6; + svg_parse_fixed(sp, sx); + // Skip to comma or closing paren + while (*sp && *sp != ',' && *sp != ')') ++sp; + if (*sp == ',') { + ++sp; + while (*sp == ' ') ++sp; + svg_parse_fixed(sp, sy); + } else { + *sy = *sx; // uniform scale + } + return true; + } + ++sp; + } + *sx = int_to_fixed(1); + *sy = int_to_fixed(1); + return false; +} + // --------------------------------------------------------------------------- // Scanline rasterizer with alpha blending (for multi-color SVGs) // --------------------------------------------------------------------------- @@ -1314,11 +1350,17 @@ inline SvgIcon svg_render(const char* svg_data, int svg_len, int target_w, int t int alpha = svg_get_element_opacity(elem_start, elem_len); + // Per-element transform (scale) + fixed_t elem_sx, elem_sy; + svg_get_element_scale(elem_start, elem_len, &elem_sx, &elem_sy); + fixed_t eff_sx = fixed_mul(scale_x, elem_sx); + fixed_t eff_sy = fixed_mul(scale_y, elem_sy); + // Extract and rasterize path int d_len = svg_get_attr(elem_start, elem_len, " d", d_buf, SVG_MAX_PATH_LEN); if (d_len > 0) { el.clear(); - svg_path_to_edges(el, d_buf, d_len, scale_x, scale_y, vb_x, vb_y); + svg_path_to_edges(el, d_buf, d_len, eff_sx, eff_sy, vb_x, vb_y); if (el.count > 0) svg_rasterize_blend(el, icon.pixels, target_w, target_h, elem_color.to_pixel(), alpha); } @@ -1349,6 +1391,11 @@ inline SvgIcon svg_render(const char* svg_data, int svg_len, int target_w, int t int alpha = svg_get_element_opacity(elem_start, elem_len); + fixed_t elem_sx, elem_sy; + svg_get_element_scale(elem_start, elem_len, &elem_sx, &elem_sy); + fixed_t eff_sx = fixed_mul(scale_x, elem_sx); + fixed_t eff_sy = fixed_mul(scale_y, elem_sy); + char attr_buf[32]; fixed_t cx = 0, cy = 0, r = 0; if (svg_get_attr(elem_start, elem_len, " cx", attr_buf, sizeof(attr_buf)) > 0) @@ -1358,10 +1405,10 @@ inline SvgIcon svg_render(const char* svg_data, int svg_len, int target_w, int t if (svg_get_attr(elem_start, elem_len, " r", attr_buf, sizeof(attr_buf)) > 0) svg_parse_fixed(attr_buf, &r); - fixed_t scx = fixed_mul(cx - vb_x, scale_x); - fixed_t scy = fixed_mul(cy - vb_y, scale_y); - fixed_t srx = fixed_mul(r, scale_x); - fixed_t sry = fixed_mul(r, scale_y); + fixed_t scx = fixed_mul(cx - vb_x, eff_sx); + fixed_t scy = fixed_mul(cy - vb_y, eff_sy); + fixed_t srx = fixed_mul(r, eff_sx); + fixed_t sry = fixed_mul(r, eff_sy); fixed_t sr = (srx + sry) >> 1; el.clear(); @@ -1395,6 +1442,11 @@ inline SvgIcon svg_render(const char* svg_data, int svg_len, int target_w, int t int alpha = svg_get_element_opacity(elem_start, elem_len); + fixed_t elem_sx, elem_sy; + svg_get_element_scale(elem_start, elem_len, &elem_sx, &elem_sy); + fixed_t eff_sx = fixed_mul(scale_x, elem_sx); + fixed_t eff_sy = fixed_mul(scale_y, elem_sy); + char attr_buf[32]; fixed_t rx_val = 0, ry_val = 0, rw = 0, rh = 0, rrx = 0, rry = 0; @@ -1411,12 +1463,12 @@ inline SvgIcon svg_render(const char* svg_data, int svg_len, int target_w, int t if (svg_get_attr(elem_start, elem_len, " ry", attr_buf, sizeof(attr_buf)) > 0) svg_parse_fixed(attr_buf, &rry); - fixed_t sx = fixed_mul(rx_val - vb_x, scale_x); - fixed_t sy = fixed_mul(ry_val - vb_y, scale_y); - fixed_t sw = fixed_mul(rw, scale_x); - fixed_t sh = fixed_mul(rh, scale_y); - fixed_t srx = fixed_mul(rrx, scale_x); - fixed_t sry = fixed_mul(rry, scale_y); + fixed_t sx = fixed_mul(rx_val - vb_x, eff_sx); + fixed_t sy = fixed_mul(ry_val - vb_y, eff_sy); + fixed_t sw = fixed_mul(rw, eff_sx); + fixed_t sh = fixed_mul(rh, eff_sy); + fixed_t srx = fixed_mul(rrx, eff_sx); + fixed_t sry = fixed_mul(rry, eff_sy); el.clear(); svg_rect_edges(el, sx, sy, sw, sh, srx, sry); diff --git a/programs/include/libc/montauk.h b/programs/include/libc/montauk.h new file mode 100644 index 0000000..f7314d3 --- /dev/null +++ b/programs/include/libc/montauk.h @@ -0,0 +1,580 @@ +/* + * montauk.h + * MontaukOS C API for user programs (TCC-compatible) + * Copyright (c) 2026 Daniel Hammer + * + * Usage: #include + * + * Provides direct access to all MontaukOS system calls from C. + * This header is self-contained and does not depend on C++ headers. +*/ + +#ifndef _MONTAUK_H +#define _MONTAUK_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ==================================================================== + Syscall numbers + ==================================================================== */ + +#define MTK_SYS_EXIT 0 +#define MTK_SYS_YIELD 1 +#define MTK_SYS_SLEEP_MS 2 +#define MTK_SYS_GETPID 3 +#define MTK_SYS_PRINT 4 +#define MTK_SYS_PUTCHAR 5 +#define MTK_SYS_OPEN 6 +#define MTK_SYS_READ 7 +#define MTK_SYS_GETSIZE 8 +#define MTK_SYS_CLOSE 9 +#define MTK_SYS_READDIR 10 +#define MTK_SYS_ALLOC 11 +#define MTK_SYS_FREE 12 +#define MTK_SYS_GETTICKS 13 +#define MTK_SYS_GETMILLISECONDS 14 +#define MTK_SYS_GETINFO 15 +#define MTK_SYS_ISKEYAVAILABLE 16 +#define MTK_SYS_GETKEY 17 +#define MTK_SYS_GETCHAR 18 +#define MTK_SYS_PING 19 +#define MTK_SYS_SPAWN 20 +#define MTK_SYS_WAITPID 23 +#define MTK_SYS_TERMSIZE 24 +#define MTK_SYS_GETARGS 25 +#define MTK_SYS_RESET 26 +#define MTK_SYS_SHUTDOWN 27 +#define MTK_SYS_GETTIME 28 +#define MTK_SYS_SOCKET 29 +#define MTK_SYS_CONNECT 30 +#define MTK_SYS_BIND 31 +#define MTK_SYS_LISTEN 32 +#define MTK_SYS_ACCEPT 33 +#define MTK_SYS_SEND 34 +#define MTK_SYS_RECV 35 +#define MTK_SYS_CLOSESOCK 36 +#define MTK_SYS_GETNETCFG 37 +#define MTK_SYS_SETNETCFG 38 +#define MTK_SYS_SENDTO 39 +#define MTK_SYS_RECVFROM 40 +#define MTK_SYS_FWRITE 41 +#define MTK_SYS_FCREATE 42 +#define MTK_SYS_TERMSCALE 43 +#define MTK_SYS_RESOLVE 44 +#define MTK_SYS_GETRANDOM 45 +#define MTK_SYS_KLOG 46 +#define MTK_SYS_MOUSESTATE 47 +#define MTK_SYS_SETMOUSEBOUNDS 48 +#define MTK_SYS_SPAWN_REDIR 49 +#define MTK_SYS_CHILDIO_READ 50 +#define MTK_SYS_CHILDIO_WRITE 51 +#define MTK_SYS_WINCREATE 54 +#define MTK_SYS_WINDESTROY 55 +#define MTK_SYS_WINPRESENT 56 +#define MTK_SYS_WINPOLL 57 +#define MTK_SYS_WINENUM 58 +#define MTK_SYS_WINMAP 59 +#define MTK_SYS_WINSENDEVENT 60 +#define MTK_SYS_PROCLIST 61 +#define MTK_SYS_KILL 62 +#define MTK_SYS_WINRESIZE 64 +#define MTK_SYS_WINSETSCALE 65 +#define MTK_SYS_WINGETSCALE 66 +#define MTK_SYS_MEMSTATS 67 +#define MTK_SYS_WINSETCURSOR 68 +#define MTK_SYS_FDELETE 77 +#define MTK_SYS_FMKDIR 78 +#define MTK_SYS_DRIVELIST 79 +#define MTK_SYS_AUDIOOPEN 80 +#define MTK_SYS_AUDIOCLOSE 81 +#define MTK_SYS_AUDIOWRITE 82 +#define MTK_SYS_AUDIOCTL 83 + +#define MTK_SOCK_TCP 1 +#define MTK_SOCK_UDP 2 + +/* Window event types */ +#define MTK_EVENT_KEY 0 +#define MTK_EVENT_MOUSE 1 +#define MTK_EVENT_RESIZE 2 +#define MTK_EVENT_CLOSE 3 +#define MTK_EVENT_SCALE 4 + +/* Audio control commands */ +#define MTK_AUDIO_SET_VOLUME 0 +#define MTK_AUDIO_GET_VOLUME 1 +#define MTK_AUDIO_GET_POS 2 +#define MTK_AUDIO_PAUSE 3 + +/* ==================================================================== + Structures + ==================================================================== */ + +typedef struct { + uint8_t scancode; + char ascii; + uint8_t pressed; + uint8_t shift; + uint8_t ctrl; + uint8_t alt; +} mtk_key_event; + +typedef struct { + int32_t x; + int32_t y; + int32_t scroll_delta; + uint8_t buttons; +} mtk_mouse_state; + +typedef struct { + uint8_t type; + uint8_t _pad[3]; + union { + mtk_key_event key; + struct { int32_t x, y, scroll; uint8_t buttons, prev_buttons; } mouse; + struct { int32_t w, h; } resize; + struct { int32_t scale; } scale; + }; +} mtk_win_event; + +typedef struct { + int32_t id; + uint32_t _pad; + uint64_t pixels; /* virtual address of pixel buffer (uint32_t*) */ +} mtk_win_result; + +typedef struct { + int32_t id; + int32_t owner_pid; + char title[64]; + int32_t width, height; + uint8_t dirty; + uint8_t cursor; + uint8_t _pad2[2]; +} mtk_win_info; + +typedef struct { + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; +} mtk_datetime; + +typedef struct { + char os_name[32]; + char os_version[32]; + uint32_t api_version; + uint32_t max_processes; +} mtk_sysinfo; + +typedef struct { + uint64_t total_bytes; + uint64_t free_bytes; + uint64_t used_bytes; + uint64_t page_size; +} mtk_memstats; + +typedef struct { + uint32_t ip_address; + uint32_t subnet_mask; + uint32_t gateway; + uint8_t mac_address[6]; + uint8_t _pad[2]; + uint32_t dns_server; +} mtk_netcfg; + +typedef struct { + int32_t pid; + int32_t parent_pid; + uint8_t state; /* 0=Free, 1=Ready, 2=Running, 3=Terminated */ + uint8_t _pad[3]; + char name[64]; + uint64_t heap_used; +} mtk_procinfo; + +/* ==================================================================== + Raw syscall wrappers + ==================================================================== */ + +static inline long _mtk_syscall0(long nr) { + long ret; + __asm__ volatile("syscall" : "=a"(ret) : "a"(nr) + : "rcx", "r11", "rdi", "rsi", "rdx", "r8", "r9", "r10", "memory"); + return ret; +} + +static inline long _mtk_syscall1(long nr, long a1) { + long ret; + __asm__ volatile( + "mov %[a1], %%rdi\n\t" + "syscall" + : "=a"(ret) + : "a"(nr), [a1] "r"(a1) + : "rcx", "r11", "rdi", "rsi", "rdx", "r8", "r9", "r10", "memory"); + return ret; +} + +static inline long _mtk_syscall2(long nr, long a1, long a2) { + long ret; + __asm__ volatile( + "mov %[a1], %%rdi\n\t" + "mov %[a2], %%rsi\n\t" + "syscall" + : "=a"(ret) + : "a"(nr), [a1] "r"(a1), [a2] "r"(a2) + : "rcx", "r11", "rdi", "rsi", "rdx", "r8", "r9", "r10", "memory"); + return ret; +} + +static inline long _mtk_syscall3(long nr, long a1, long a2, long a3) { + long ret; + __asm__ volatile( + "mov %[a1], %%rdi\n\t" + "mov %[a2], %%rsi\n\t" + "mov %[a3], %%rdx\n\t" + "syscall" + : "=a"(ret) + : "a"(nr), [a1] "r"(a1), [a2] "r"(a2), [a3] "r"(a3) + : "rcx", "r11", "rdi", "rsi", "rdx", "r8", "r9", "r10", "memory"); + return ret; +} + +static inline long _mtk_syscall4(long nr, long a1, long a2, long a3, long a4) { + long ret; + __asm__ volatile( + "mov %[a1], %%rdi\n\t" + "mov %[a2], %%rsi\n\t" + "mov %[a3], %%rdx\n\t" + "mov %[a4], %%r10\n\t" + "syscall" + : "=a"(ret) + : "a"(nr), [a1] "r"(a1), [a2] "r"(a2), [a3] "r"(a3), [a4] "r"(a4) + : "rcx", "r11", "rdi", "rsi", "rdx", "r8", "r9", "r10", "memory"); + return ret; +} + +static inline long _mtk_syscall5(long nr, long a1, long a2, long a3, long a4, long a5) { + long ret; + __asm__ volatile( + "mov %[a1], %%rdi\n\t" + "mov %[a2], %%rsi\n\t" + "mov %[a3], %%rdx\n\t" + "mov %[a4], %%r10\n\t" + "mov %[a5], %%r8\n\t" + "syscall" + : "=a"(ret) + : "a"(nr), [a1] "r"(a1), [a2] "r"(a2), [a3] "r"(a3), [a4] "r"(a4), [a5] "r"(a5) + : "rcx", "r11", "rdi", "rsi", "rdx", "r8", "r9", "r10", "memory"); + return ret; +} + +/* ==================================================================== + Process management + ==================================================================== */ + +static inline void mtk_exit(int code) { + _mtk_syscall1(MTK_SYS_EXIT, (long)code); +} + +static inline void mtk_yield(void) { + _mtk_syscall0(MTK_SYS_YIELD); +} + +static inline void mtk_sleep_ms(unsigned long ms) { + _mtk_syscall1(MTK_SYS_SLEEP_MS, (long)ms); +} + +static inline int mtk_getpid(void) { + return (int)_mtk_syscall0(MTK_SYS_GETPID); +} + +static inline int mtk_spawn(const char *path, const char *args) { + return (int)_mtk_syscall2(MTK_SYS_SPAWN, (long)path, (long)args); +} + +static inline void mtk_waitpid(int pid) { + _mtk_syscall1(MTK_SYS_WAITPID, (long)pid); +} + +static inline int mtk_kill(int pid) { + return (int)_mtk_syscall1(MTK_SYS_KILL, (long)pid); +} + +static inline int mtk_proclist(mtk_procinfo *buf, int max) { + return (int)_mtk_syscall2(MTK_SYS_PROCLIST, (long)buf, (long)max); +} + +static inline int mtk_getargs(char *buf, unsigned long max_len) { + return (int)_mtk_syscall2(MTK_SYS_GETARGS, (long)buf, (long)max_len); +} + +/* ==================================================================== + Console I/O + ==================================================================== */ + +static inline void mtk_print(const char *text) { + _mtk_syscall1(MTK_SYS_PRINT, (long)text); +} + +static inline void mtk_putchar(char c) { + _mtk_syscall1(MTK_SYS_PUTCHAR, (long)c); +} + +static inline char mtk_getchar(void) { + return (char)_mtk_syscall0(MTK_SYS_GETCHAR); +} + +static inline int mtk_is_key_available(void) { + return (int)_mtk_syscall0(MTK_SYS_ISKEYAVAILABLE); +} + +static inline void mtk_getkey(mtk_key_event *out) { + _mtk_syscall1(MTK_SYS_GETKEY, (long)out); +} + +/* ==================================================================== + File I/O + ==================================================================== */ + +static inline int mtk_open(const char *path) { + return (int)_mtk_syscall1(MTK_SYS_OPEN, (long)path); +} + +static inline int mtk_read(int handle, uint8_t *buf, unsigned long offset, unsigned long size) { + return (int)_mtk_syscall4(MTK_SYS_READ, (long)handle, (long)buf, (long)offset, (long)size); +} + +static inline int mtk_write(int handle, const uint8_t *buf, unsigned long offset, unsigned long size) { + return (int)_mtk_syscall4(MTK_SYS_FWRITE, (long)handle, (long)buf, (long)offset, (long)size); +} + +static inline unsigned long mtk_getsize(int handle) { + return (unsigned long)_mtk_syscall1(MTK_SYS_GETSIZE, (long)handle); +} + +static inline void mtk_close(int handle) { + _mtk_syscall1(MTK_SYS_CLOSE, (long)handle); +} + +static inline int mtk_create(const char *path) { + return (int)_mtk_syscall1(MTK_SYS_FCREATE, (long)path); +} + +static inline int mtk_delete(const char *path) { + return (int)_mtk_syscall1(MTK_SYS_FDELETE, (long)path); +} + +static inline int mtk_mkdir(const char *path) { + return (int)_mtk_syscall1(MTK_SYS_FMKDIR, (long)path); +} + +static inline int mtk_readdir(const char *path, const char **names, int max) { + return (int)_mtk_syscall3(MTK_SYS_READDIR, (long)path, (long)names, (long)max); +} + +/* ==================================================================== + Memory + ==================================================================== */ + +static inline void *mtk_alloc_pages(unsigned long bytes) { + return (void *)_mtk_syscall1(MTK_SYS_ALLOC, (long)bytes); +} + +static inline void mtk_free_pages(void *ptr) { + _mtk_syscall1(MTK_SYS_FREE, (long)ptr); +} + +static inline void mtk_get_memstats(mtk_memstats *out) { + _mtk_syscall1(MTK_SYS_MEMSTATS, (long)out); +} + +/* ==================================================================== + Timekeeping + ==================================================================== */ + +static inline unsigned long mtk_get_ticks(void) { + return (unsigned long)_mtk_syscall0(MTK_SYS_GETTICKS); +} + +static inline unsigned long mtk_get_ms(void) { + return (unsigned long)_mtk_syscall0(MTK_SYS_GETMILLISECONDS); +} + +static inline void mtk_gettime(mtk_datetime *out) { + _mtk_syscall1(MTK_SYS_GETTIME, (long)out); +} + +/* ==================================================================== + System info + ==================================================================== */ + +static inline void mtk_get_info(mtk_sysinfo *info) { + _mtk_syscall1(MTK_SYS_GETINFO, (long)info); +} + +static inline long mtk_getrandom(void *buf, unsigned int len) { + return _mtk_syscall2(MTK_SYS_GETRANDOM, (long)buf, (long)len); +} + +/* ==================================================================== + Terminal + ==================================================================== */ + +static inline void mtk_termsize(int *cols, int *rows) { + unsigned long r = (unsigned long)_mtk_syscall0(MTK_SYS_TERMSIZE); + if (cols) *cols = (int)(r & 0xFFFFFFFF); + if (rows) *rows = (int)(r >> 32); +} + +/* ==================================================================== + Window server + ==================================================================== */ + +static inline int mtk_win_create(const char *title, int w, int h, mtk_win_result *result) { + return (int)_mtk_syscall4(MTK_SYS_WINCREATE, (long)title, (long)w, (long)h, (long)result); +} + +static inline int mtk_win_destroy(int id) { + return (int)_mtk_syscall1(MTK_SYS_WINDESTROY, (long)id); +} + +static inline unsigned long mtk_win_present(int id) { + return (unsigned long)_mtk_syscall1(MTK_SYS_WINPRESENT, (long)id); +} + +static inline int mtk_win_poll(int id, mtk_win_event *event) { + return (int)_mtk_syscall2(MTK_SYS_WINPOLL, (long)id, (long)event); +} + +static inline unsigned long mtk_win_resize(int id, int w, int h) { + return (unsigned long)_mtk_syscall3(MTK_SYS_WINRESIZE, (long)id, (long)w, (long)h); +} + +static inline int mtk_win_enumerate(mtk_win_info *info, int max) { + return (int)_mtk_syscall2(MTK_SYS_WINENUM, (long)info, (long)max); +} + +static inline int mtk_win_setcursor(int id, int cursor) { + return (int)_mtk_syscall2(MTK_SYS_WINSETCURSOR, (long)id, (long)cursor); +} + +static inline int mtk_win_setscale(int scale) { + return (int)_mtk_syscall1(MTK_SYS_WINSETSCALE, (long)scale); +} + +static inline int mtk_win_getscale(void) { + return (int)_mtk_syscall0(MTK_SYS_WINGETSCALE); +} + +/* ==================================================================== + Mouse + ==================================================================== */ + +static inline void mtk_get_mouse(mtk_mouse_state *out) { + _mtk_syscall1(MTK_SYS_MOUSESTATE, (long)out); +} + +/* ==================================================================== + Networking + ==================================================================== */ + +static inline int mtk_socket(int type) { + return (int)_mtk_syscall1(MTK_SYS_SOCKET, (long)type); +} + +static inline int mtk_connect(int fd, uint32_t ip, uint16_t port) { + return (int)_mtk_syscall3(MTK_SYS_CONNECT, (long)fd, (long)ip, (long)port); +} + +static inline int mtk_bind(int fd, uint16_t port) { + return (int)_mtk_syscall2(MTK_SYS_BIND, (long)fd, (long)port); +} + +static inline int mtk_listen(int fd) { + return (int)_mtk_syscall1(MTK_SYS_LISTEN, (long)fd); +} + +static inline int mtk_accept(int fd) { + return (int)_mtk_syscall1(MTK_SYS_ACCEPT, (long)fd); +} + +static inline int mtk_send(int fd, const void *data, uint32_t len) { + return (int)_mtk_syscall3(MTK_SYS_SEND, (long)fd, (long)data, (long)len); +} + +static inline int mtk_recv(int fd, void *buf, uint32_t max_len) { + return (int)_mtk_syscall3(MTK_SYS_RECV, (long)fd, (long)buf, (long)max_len); +} + +static inline int mtk_closesocket(int fd) { + return (int)_mtk_syscall1(MTK_SYS_CLOSESOCK, (long)fd); +} + +static inline uint32_t mtk_resolve(const char *hostname) { + return (uint32_t)_mtk_syscall1(MTK_SYS_RESOLVE, (long)hostname); +} + +static inline int mtk_ping(uint32_t ip, uint32_t timeout_ms) { + return (int)_mtk_syscall2(MTK_SYS_PING, (long)ip, (long)timeout_ms); +} + +static inline void mtk_get_netcfg(mtk_netcfg *out) { + _mtk_syscall1(MTK_SYS_GETNETCFG, (long)out); +} + +/* ==================================================================== + Audio + ==================================================================== */ + +static inline int mtk_audio_open(uint32_t sample_rate, uint8_t channels, uint8_t bits) { + return (int)_mtk_syscall3(MTK_SYS_AUDIOOPEN, (long)sample_rate, (long)channels, (long)bits); +} + +static inline void mtk_audio_close(int handle) { + _mtk_syscall1(MTK_SYS_AUDIOCLOSE, (long)handle); +} + +static inline int mtk_audio_write(int handle, const void *data, uint32_t size) { + return (int)_mtk_syscall3(MTK_SYS_AUDIOWRITE, (long)handle, (long)data, (long)size); +} + +static inline int mtk_audio_ctl(int handle, int cmd, int value) { + return (int)_mtk_syscall3(MTK_SYS_AUDIOCTL, (long)handle, (long)cmd, (long)value); +} + +/* ==================================================================== + Power management + ==================================================================== */ + +static inline void mtk_reset(void) { + _mtk_syscall0(MTK_SYS_RESET); +} + +static inline void mtk_shutdown(void) { + _mtk_syscall0(MTK_SYS_SHUTDOWN); +} + +/* ==================================================================== + Pixel helpers (for window server apps) + ==================================================================== */ + +static inline uint32_t mtk_rgb(uint8_t r, uint8_t g, uint8_t b) { + return 0xFF000000 | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; +} + +static inline uint32_t mtk_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; +} + +#ifdef __cplusplus +} +#endif + +#endif /* _MONTAUK_H */ diff --git a/programs/include/libc/unistd.h b/programs/include/libc/unistd.h index fe56976..5793856 100644 --- a/programs/include/libc/unistd.h +++ b/programs/include/libc/unistd.h @@ -12,6 +12,7 @@ extern "C" { int read(int fd, void *buf, size_t count); int write(int fd, const void *buf, size_t count); int close(int fd); +long lseek(int fd, long offset, int whence); #ifdef __cplusplus } diff --git a/programs/lib/libc/libc.c b/programs/lib/libc/libc.c index ad0833b..52a9900 100644 --- a/programs/lib/libc/libc.c +++ b/programs/lib/libc/libc.c @@ -9,6 +9,10 @@ #include #include #include +#include +#include +#include +#include /* ======================================================================== Raw syscall wrappers (C versions matching kernel ABI) @@ -32,6 +36,31 @@ static inline long _zos_syscall1(long nr, long a1) { return ret; } +static inline long _zos_syscall2(long nr, long a1, long a2) { + long ret; + __asm__ volatile( + "mov %[a1], %%rdi\n\t" + "mov %[a2], %%rsi\n\t" + "syscall" + : "=a"(ret) + : "a"(nr), [a1] "r"(a1), [a2] "r"(a2) + : "rcx", "r11", "rdi", "rsi", "rdx", "r8", "r9", "r10", "memory"); + return ret; +} + +static inline long _zos_syscall3(long nr, long a1, long a2, long a3) { + long ret; + __asm__ volatile( + "mov %[a1], %%rdi\n\t" + "mov %[a2], %%rsi\n\t" + "mov %[a3], %%rdx\n\t" + "syscall" + : "=a"(ret) + : "a"(nr), [a1] "r"(a1), [a2] "r"(a2), [a3] "r"(a3) + : "rcx", "r11", "rdi", "rsi", "rdx", "r8", "r9", "r10", "memory"); + return ret; +} + static inline long _zos_syscall4(long nr, long a1, long a2, long a3, long a4) { long ret; __asm__ volatile( @@ -50,8 +79,21 @@ static inline long _zos_syscall4(long nr, long a1, long a2, long a3, long a4) { #define SYS_EXIT 0 #define SYS_PRINT 4 #define SYS_PUTCHAR 5 +#define SYS_OPEN 6 +#define SYS_READ 7 +#define SYS_GETSIZE 8 +#define SYS_CLOSE 9 +#define SYS_READDIR 10 #define SYS_ALLOC 11 #define SYS_FREE 12 +#define SYS_GETCHAR 18 +#define SYS_SPAWN 20 +#define SYS_WAITPID 23 +#define SYS_GETARGS 25 +#define SYS_FWRITE 41 +#define SYS_FCREATE 42 +#define SYS_FDELETE 77 +#define SYS_FMKDIR 78 /* ======================================================================== errno @@ -596,8 +638,11 @@ void abort(void) { } int system(const char *command) { - (void)command; - return -1; + if (command == NULL) return -1; + int pid = (int)_zos_syscall2(SYS_SPAWN, (long)command, 0L); + if (pid < 0) return -1; + _zos_syscall1(SYS_WAITPID, (long)pid); + return 0; } /* ======================================================================== @@ -859,3 +904,619 @@ void __assert_fail(const char *expr, const char *file, int line, const char *fun (void)line; (void)func; abort(); } + +/* ======================================================================== + stdio.h FILE-based I/O + ======================================================================== */ + +/* Static FILE objects for standard streams */ +static FILE _stdin_file = { .handle = -1, .pos = 0, .size = 0, .eof = 0, + .error = 0, .is_std = 1, .ungetc_buf = -1 }; +static FILE _stdout_file = { .handle = -1, .pos = 0, .size = 0, .eof = 0, + .error = 0, .is_std = 2, .ungetc_buf = -1 }; +static FILE _stderr_file = { .handle = -1, .pos = 0, .size = 0, .eof = 0, + .error = 0, .is_std = 3, .ungetc_buf = -1 }; + +FILE *stdin = &_stdin_file; +FILE *stdout = &_stdout_file; +FILE *stderr = &_stderr_file; + +FILE *fopen(const char *path, const char *mode) { + if (path == NULL || mode == NULL) return NULL; + + int handle = -1; + int want_read = 0; + int want_write = 0; + int want_append = 0; + + if (mode[0] == 'r') { + want_read = 1; + if (mode[1] == '+') want_write = 1; + } else if (mode[0] == 'w') { + want_write = 1; + if (mode[1] == '+') want_read = 1; + /* Truncate: delete then create */ + _zos_syscall1(SYS_FDELETE, (long)path); + handle = (int)_zos_syscall1(SYS_FCREATE, (long)path); + if (handle < 0) return NULL; + } else if (mode[0] == 'a') { + want_write = 1; + want_append = 1; + if (mode[1] == '+') want_read = 1; + /* Try open existing, create if not found */ + handle = (int)_zos_syscall1(SYS_OPEN, (long)path); + if (handle < 0) { + handle = (int)_zos_syscall1(SYS_FCREATE, (long)path); + if (handle < 0) return NULL; + } + } else { + return NULL; + } + + /* For read and read+ modes, just open existing */ + if (mode[0] == 'r') { + handle = (int)_zos_syscall1(SYS_OPEN, (long)path); + if (handle < 0) return NULL; + } + + unsigned long fileSize = (unsigned long)_zos_syscall1(SYS_GETSIZE, (long)handle); + + FILE *f = (FILE *)malloc(sizeof(FILE)); + if (f == NULL) { + _zos_syscall1(SYS_CLOSE, (long)handle); + return NULL; + } + + f->handle = handle; + f->size = fileSize; + f->pos = want_append ? fileSize : 0; + f->eof = 0; + f->error = 0; + f->is_std = 0; + f->ungetc_buf = -1; + + (void)want_read; + (void)want_write; + + return f; +} + +int fclose(FILE *stream) { + if (stream == NULL) return EOF; + if (stream->is_std) return 0; + + _zos_syscall1(SYS_CLOSE, (long)stream->handle); + free(stream); + return 0; +} + +size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { + if (stream == NULL || ptr == NULL || size == 0 || nmemb == 0) return 0; + + if (stream->is_std == 1) { + /* stdin: read characters via SYS_GETCHAR */ + size_t total = size * nmemb; + char *dst = (char *)ptr; + size_t i; + for (i = 0; i < total; i++) { + int c = (int)_zos_syscall0(SYS_GETCHAR); + if (c <= 0) { stream->eof = 1; break; } + dst[i] = (char)c; + } + return i / size; + } + + size_t total = size * nmemb; + size_t remaining = (stream->pos < stream->size) ? stream->size - stream->pos : 0; + if (total > remaining) { + total = remaining; + stream->eof = 1; + } + if (total == 0) return 0; + + int ret = (int)_zos_syscall4(SYS_READ, (long)stream->handle, + (long)ptr, (long)stream->pos, (long)total); + if (ret < 0) { + stream->error = 1; + return 0; + } + + stream->pos += (unsigned long)ret; + return (size_t)ret / size; +} + +size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { + if (stream == NULL || ptr == NULL || size == 0 || nmemb == 0) return 0; + + if (stream->is_std) { + /* stdout/stderr: print via SYS_PRINT/SYS_PUTCHAR */ + size_t total = size * nmemb; + const char *src = (const char *)ptr; + for (size_t i = 0; i < total; i++) + _zos_syscall1(SYS_PUTCHAR, (long)(unsigned char)src[i]); + return nmemb; + } + + size_t total = size * nmemb; + int ret = (int)_zos_syscall4(SYS_FWRITE, (long)stream->handle, + (long)ptr, (long)stream->pos, (long)total); + if (ret < 0) { + stream->error = 1; + return 0; + } + + stream->pos += (unsigned long)ret; + /* Update size if we wrote past the old end */ + if (stream->pos > stream->size) + stream->size = stream->pos; + return (size_t)ret / size; +} + +int fseek(FILE *stream, long offset, int whence) { + if (stream == NULL || stream->is_std) return -1; + + unsigned long newpos; + switch (whence) { + case SEEK_SET: newpos = (unsigned long)offset; break; + case SEEK_CUR: newpos = stream->pos + (unsigned long)offset; break; + case SEEK_END: newpos = stream->size + (unsigned long)offset; break; + default: return -1; + } + + stream->pos = newpos; + stream->eof = 0; + return 0; +} + +long ftell(FILE *stream) { + if (stream == NULL) return -1; + return (long)stream->pos; +} + +int fflush(FILE *stream) { + /* No buffering in this implementation */ + (void)stream; + return 0; +} + +int feof(FILE *stream) { + if (stream == NULL) return 0; + return stream->eof; +} + +int ferror(FILE *stream) { + if (stream == NULL) return 0; + return stream->error; +} + +void clearerr(FILE *stream) { + if (stream == NULL) return; + stream->eof = 0; + stream->error = 0; +} + +int fgetc(FILE *stream) { + if (stream == NULL) return EOF; + + /* Check ungetc buffer first */ + if (stream->ungetc_buf >= 0) { + int c = stream->ungetc_buf; + stream->ungetc_buf = -1; + return c; + } + + if (stream->is_std == 1) { + int c = (int)_zos_syscall0(SYS_GETCHAR); + if (c <= 0) { stream->eof = 1; return EOF; } + return c; + } + + if (stream->pos >= stream->size) { + stream->eof = 1; + return EOF; + } + + unsigned char c; + int ret = (int)_zos_syscall4(SYS_READ, (long)stream->handle, + (long)&c, (long)stream->pos, 1L); + if (ret <= 0) { + stream->eof = 1; + return EOF; + } + + stream->pos++; + return (int)c; +} + +int getc(FILE *stream) { + return fgetc(stream); +} + +int ungetc(int c, FILE *stream) { + if (stream == NULL || c == EOF) return EOF; + stream->ungetc_buf = c; + stream->eof = 0; + return c; +} + +char *fgets(char *s, int size, FILE *stream) { + if (s == NULL || size <= 0 || stream == NULL) return NULL; + + int i = 0; + while (i < size - 1) { + int c = fgetc(stream); + if (c == EOF) { + if (i == 0) return NULL; + break; + } + s[i++] = (char)c; + if (c == '\n') break; + } + s[i] = '\0'; + return s; +} + +int fputs(const char *s, FILE *stream) { + if (s == NULL || stream == NULL) return EOF; + + size_t len = strlen(s); + size_t written = fwrite(s, 1, len, stream); + return (written == len) ? 0 : EOF; +} + +int fprintf(FILE *stream, const char *fmt, ...) { + char buf[4096]; + va_list ap; + va_start(ap, fmt); + int n = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + if (stream == NULL || stream->is_std) { + _zos_syscall1(SYS_PRINT, (long)buf); + } else { + fwrite(buf, 1, (size_t)(n > 0 ? n : 0), stream); + } + return n; +} + +int vfprintf(FILE *stream, const char *fmt, va_list ap) { + char buf[4096]; + int n = vsnprintf(buf, sizeof(buf), fmt, ap); + + if (stream == NULL || stream->is_std) { + _zos_syscall1(SYS_PRINT, (long)buf); + } else { + fwrite(buf, 1, (size_t)(n > 0 ? n : 0), stream); + } + return n; +} + +int vprintf(const char *fmt, va_list ap) { + return vfprintf(stdout, fmt, ap); +} + +int vsprintf(char *str, const char *fmt, va_list ap) { + return vsnprintf(str, (size_t)-1, fmt, ap); +} + +int remove(const char *path) { + if (path == NULL) return -1; + return (int)_zos_syscall1(SYS_FDELETE, (long)path); +} + +int rename(const char *oldpath, const char *newpath) { + /* No atomic rename syscall -- copy + delete */ + if (oldpath == NULL || newpath == NULL) return -1; + + int src = (int)_zos_syscall1(SYS_OPEN, (long)oldpath); + if (src < 0) return -1; + + unsigned long sz = (unsigned long)_zos_syscall1(SYS_GETSIZE, (long)src); + + /* Create destination */ + _zos_syscall1(SYS_FDELETE, (long)newpath); + int dst = (int)_zos_syscall1(SYS_FCREATE, (long)newpath); + if (dst < 0) { + _zos_syscall1(SYS_CLOSE, (long)src); + return -1; + } + + /* Copy in chunks */ + char copybuf[4096]; + unsigned long off = 0; + while (off < sz) { + unsigned long chunk = sz - off; + if (chunk > sizeof(copybuf)) chunk = sizeof(copybuf); + int r = (int)_zos_syscall4(SYS_READ, (long)src, + (long)copybuf, (long)off, (long)chunk); + if (r <= 0) break; + _zos_syscall4(SYS_FWRITE, (long)dst, + (long)copybuf, (long)off, (long)r); + off += (unsigned long)r; + } + + _zos_syscall1(SYS_CLOSE, (long)src); + _zos_syscall1(SYS_CLOSE, (long)dst); + _zos_syscall1(SYS_FDELETE, (long)oldpath); + return 0; +} + +void perror(const char *s) { + if (s != NULL && s[0] != '\0') { + _zos_syscall1(SYS_PRINT, (long)s); + _zos_syscall1(SYS_PRINT, (long)": "); + } + _zos_syscall1(SYS_PRINT, (long)"error\n"); +} + +FILE *tmpfile(void) { + return NULL; +} + +char *tmpnam(char *s) { + (void)s; + return NULL; +} + +/* ======================================================================== + sscanf (minimal: %d, %x, %s, %c, %u, %ld, %lu) + ======================================================================== */ + +int sscanf(const char *str, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int matched = 0; + const char *s = str; + + while (*fmt) { + if (*fmt == '%') { + fmt++; + int is_long = 0; + if (*fmt == 'l') { is_long = 1; fmt++; } + + if (*fmt == 'd' || *fmt == 'i') { + while (isspace((unsigned char)*s)) s++; + int neg = 0; + if (*s == '-') { neg = 1; s++; } + else if (*s == '+') s++; + if (!isdigit((unsigned char)*s)) goto done; + long val = 0; + while (isdigit((unsigned char)*s)) + val = val * 10 + (*s++ - '0'); + if (neg) val = -val; + if (is_long) *va_arg(ap, long *) = val; + else *va_arg(ap, int *) = (int)val; + matched++; + } else if (*fmt == 'u') { + while (isspace((unsigned char)*s)) s++; + if (!isdigit((unsigned char)*s)) goto done; + unsigned long val = 0; + while (isdigit((unsigned char)*s)) + val = val * 10 + (unsigned long)(*s++ - '0'); + if (is_long) *va_arg(ap, unsigned long *) = val; + else *va_arg(ap, unsigned int *) = (unsigned int)val; + matched++; + } else if (*fmt == 'x' || *fmt == 'X') { + while (isspace((unsigned char)*s)) s++; + if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) s += 2; + if (!isxdigit((unsigned char)*s)) goto done; + unsigned long val = 0; + while (isxdigit((unsigned char)*s)) { + int d; + if (*s >= '0' && *s <= '9') d = *s - '0'; + else if (*s >= 'a' && *s <= 'f') d = *s - 'a' + 10; + else d = *s - 'A' + 10; + val = val * 16 + (unsigned long)d; + s++; + } + if (is_long) *va_arg(ap, unsigned long *) = val; + else *va_arg(ap, unsigned int *) = (unsigned int)val; + matched++; + } else if (*fmt == 's') { + while (isspace((unsigned char)*s)) s++; + char *dst = va_arg(ap, char *); + if (*s == '\0') goto done; + while (*s && !isspace((unsigned char)*s)) + *dst++ = *s++; + *dst = '\0'; + matched++; + } else if (*fmt == 'c') { + if (*s == '\0') goto done; + *va_arg(ap, char *) = *s++; + matched++; + } else if (*fmt == '%') { + if (*s != '%') goto done; + s++; + } + fmt++; + } else if (isspace((unsigned char)*fmt)) { + while (isspace((unsigned char)*s)) s++; + fmt++; + } else { + if (*s != *fmt) goto done; + s++; + fmt++; + } + } + +done: + va_end(ap); + return matched; +} + +/* ======================================================================== + fcntl.h / unistd.h POSIX-style file I/O + ======================================================================== */ + +/* fd position tracking for POSIX read/write (MontaukOS uses explicit offsets) */ +#define _FD_POS_MAX 64 +static unsigned long _fd_pos[_FD_POS_MAX]; + +int open(const char *path, int flags, ...) { + if (path == NULL) return -1; + int h; + + if (flags & 0x40 /* O_CREAT */) { + _zos_syscall1(SYS_FDELETE, (long)path); + h = (int)_zos_syscall1(SYS_FCREATE, (long)path); + } else { + h = (int)_zos_syscall1(SYS_OPEN, (long)path); + } + + if (h >= 0 && h < _FD_POS_MAX) + _fd_pos[h] = 0; + return h; +} + +int read(int fd, void *buf, size_t count) { + if (buf == NULL) return -1; + unsigned long pos = (fd >= 0 && fd < _FD_POS_MAX) ? _fd_pos[fd] : 0; + int ret = (int)_zos_syscall4(SYS_READ, (long)fd, (long)buf, (long)pos, (long)count); + if (ret > 0 && fd >= 0 && fd < _FD_POS_MAX) + _fd_pos[fd] += (unsigned long)ret; + return ret; +} + +int write(int fd, const void *buf, size_t count) { + if (buf == NULL) return -1; + unsigned long pos = (fd >= 0 && fd < _FD_POS_MAX) ? _fd_pos[fd] : 0; + int ret = (int)_zos_syscall4(SYS_FWRITE, (long)fd, (long)buf, (long)pos, (long)count); + if (ret > 0 && fd >= 0 && fd < _FD_POS_MAX) + _fd_pos[fd] += (unsigned long)ret; + return ret; +} + +int close(int fd) { + if (fd >= 0 && fd < _FD_POS_MAX) + _fd_pos[fd] = 0; + _zos_syscall1(SYS_CLOSE, (long)fd); + return 0; +} + +long lseek(int fd, long offset, int whence) { + unsigned long pos = (fd >= 0 && fd < _FD_POS_MAX) ? _fd_pos[fd] : 0; + unsigned long newpos; + switch (whence) { + case 0: /* SEEK_SET */ + newpos = (unsigned long)offset; + break; + case 1: /* SEEK_CUR */ + newpos = pos + (unsigned long)offset; + break; + case 2: /* SEEK_END */ + newpos = (unsigned long)_zos_syscall1(SYS_GETSIZE, (long)fd) + (unsigned long)offset; + break; + default: + return -1; + } + if (fd >= 0 && fd < _FD_POS_MAX) + _fd_pos[fd] = newpos; + return (long)newpos; +} + +/* ======================================================================== + sys/stat.h functions + ======================================================================== */ + +int mkdir(const char *path, unsigned int mode) { + (void)mode; + if (path == NULL) return -1; + return (int)_zos_syscall1(SYS_FMKDIR, (long)path); +} + +int stat(const char *path, struct stat *buf) { + if (path == NULL || buf == NULL) return -1; + int h = (int)_zos_syscall1(SYS_OPEN, (long)path); + if (h < 0) return -1; + buf->st_size = (unsigned long)_zos_syscall1(SYS_GETSIZE, (long)h); + _zos_syscall1(SYS_CLOSE, (long)h); + return 0; +} + +int fstat(int fd, struct stat *buf) { + if (buf == NULL) return -1; + buf->st_size = (unsigned long)_zos_syscall1(SYS_GETSIZE, (long)fd); + return 0; +} + +/* ======================================================================== + stdlib.h: system() and atexit() + ======================================================================== */ + +static void (*_atexit_funcs[32])(void); +static int _atexit_count = 0; + +int atexit(void (*func)(void)) { + if (_atexit_count >= 32 || func == NULL) return -1; + _atexit_funcs[_atexit_count++] = func; + return 0; +} + +/* ======================================================================== + stdlib.h: qsort + ======================================================================== */ + +void qsort(void *base, size_t nmemb, size_t size, + int (*compar)(const void *, const void *)) { + if (nmemb < 2 || base == NULL || compar == NULL) return; + + /* Simple insertion sort for small arrays, good enough for libc */ + unsigned char *b = (unsigned char *)base; + unsigned char tmp[256]; + int use_heap = (size > sizeof(tmp)); + unsigned char *t = use_heap ? (unsigned char *)malloc(size) : tmp; + if (t == NULL) return; + + for (size_t i = 1; i < nmemb; i++) { + unsigned char *cur = b + i * size; + size_t j = i; + while (j > 0) { + unsigned char *prev = b + (j - 1) * size; + if (compar(prev, cur) <= 0) break; + j--; + cur = prev; + } + if (j != i) { + unsigned char *dst = b + j * size; + unsigned char *src = b + i * size; + memcpy(t, src, size); + memmove(dst + size, dst, (i - j) * size); + memcpy(dst, t, size); + } + } + + if (use_heap) free(t); +} + +/* ======================================================================== + stdlib.h: rand / srand + ======================================================================== */ + +static unsigned int _rand_seed = 1; + +int rand(void) { + _rand_seed = _rand_seed * 1103515245 + 12345; + return (int)((_rand_seed >> 16) & 0x7fff); +} + +void srand(unsigned int seed) { + _rand_seed = seed; +} + +div_t div(int numer, int denom) { + div_t r; + r.quot = numer / denom; + r.rem = numer % denom; + return r; +} + +ldiv_t ldiv(long numer, long denom) { + ldiv_t r; + r.quot = numer / denom; + r.rem = numer % denom; + return r; +} + +long atol(const char *s) { + return strtol(s, NULL, 10); +} diff --git a/programs/lib/libc/obj/libc.o b/programs/lib/libc/obj/libc.o index 8955356ab6e757c63d166e9e49ef3dfbadb3e971..e5031b446c2e04542f136edca452c86ab6745b2a 100644 GIT binary patch literal 186120 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 C=4`(J diff --git a/programs/src/desktop/apps/app_filemanager.cpp b/programs/src/desktop/apps/app_filemanager.cpp index 492b7e8..ef57b5e 100644 --- a/programs/src/desktop/apps/app_filemanager.cpp +++ b/programs/src/desktop/apps/app_filemanager.cpp @@ -5,6 +5,7 @@ */ #include "apps_common.hpp" +#include // ============================================================================ // File Manager state @@ -18,7 +19,7 @@ struct FileManagerState { int history_pos; int history_count; char entry_names[64][64]; - int entry_types[64]; // 0=file, 1=directory, 2=executable, 3=drive + int entry_types[64]; // 0=file, 1=dir, 2=exec, 3=drive, 4=home, 5=apps, 6=app, 7=special_dir int entry_sizes[64]; int entry_count; int selected; @@ -31,6 +32,39 @@ struct FileManagerState { bool grid_view; bool at_drives_root; int drive_indices[FM_MAX_DRIVES]; // which drive number each entry maps to + + // Clipboard + char clipboard_path[256]; + bool clipboard_has_data; + bool clipboard_is_cut; + + // Context menu + bool ctx_open; + int ctx_x, ctx_y; + int ctx_target_idx; // -1 = background + int ctx_items[8]; + int ctx_item_count; + int ctx_hover; + + // Rename + bool rename_active; + int rename_idx; + char rename_buf[64]; + int rename_cursor; + int rename_len; + + // Path bar editing + bool pathbar_editing; + char pathbar_buf[256]; + int pathbar_cursor; + int pathbar_len; + + // Apps view + bool at_apps_view; + int app_map[16]; // entry index -> external_apps[] index + SvgIcon app_icons_lg[16]; // 48x48 icons for grid view + SvgIcon app_icons_sm[16]; // 16x16 icons for list view + int app_icon_count; }; static constexpr int FM_TOOLBAR_H = 32; @@ -43,6 +77,50 @@ static constexpr int FM_GRID_CELL_H = 80; static constexpr int FM_GRID_ICON = 48; static constexpr int FM_GRID_PAD = 4; +// Special user folders: name, icon filename, index into DesktopState arrays +static constexpr int SF_COUNT = 6; +static const char* sf_names[SF_COUNT] = { + "Documents", "Desktop", "Music", "Videos", "Pictures", "Downloads" +}; +static const char* sf_icons[SF_COUNT] = { + "folder-blue-documents.svg", "folder-blue-desktop.svg", + "folder-blue-music.svg", "folder-blue-videos.svg", + "folder-blue-pictures.svg", "folder-blue-downloads.svg" +}; + +// Return special folder index (0-5) or -1 if not a special folder name +static int special_folder_index(const char* name) { + for (int i = 0; i < SF_COUNT; i++) { + if (montauk::streq(name, sf_names[i])) return i; + } + return -1; +} + +// Context menu action codes +static constexpr int CTX_OPEN = 0; +static constexpr int CTX_COPY = 1; +static constexpr int CTX_CUT = 2; +static constexpr int CTX_PASTE = 3; +static constexpr int CTX_RENAME = 4; +static constexpr int CTX_DELETE = 5; +static constexpr int CTX_NEW_FOLDER = 6; + +static constexpr int CTX_MENU_W = 140; +static constexpr int CTX_ITEM_H = 24; + +static const char* ctx_label(int action) { + switch (action) { + case CTX_OPEN: return "Open"; + case CTX_COPY: return "Copy"; + case CTX_CUT: return "Cut"; + case CTX_PASTE: return "Paste"; + case CTX_RENAME: return "Rename"; + case CTX_DELETE: return "Delete"; + case CTX_NEW_FOLDER: return "New Folder"; + default: return "?"; + } +} + // ============================================================================ // File type detection // ============================================================================ @@ -91,6 +169,30 @@ static int detect_file_type(const char* name, bool is_dir) { return 0; } +// Forward declarations +static void filemanager_free_app_icons(FileManagerState* fm); + +// ============================================================================ +// Path helpers +// ============================================================================ + +static void filemanager_build_fullpath(char* out, int out_max, + const char* dir, const char* name) { + montauk::strcpy(out, dir); + int plen = montauk::slen(out); + if (plen > 0 && out[plen - 1] != '/') str_append(out, "/", out_max); + str_append(out, name, out_max); +} + +// Extract basename from a path (pointer into the path string) +static const char* path_basename(const char* path) { + const char* last = path; + for (const char* p = path; *p; p++) { + if (*p == '/' && *(p + 1)) last = p + 1; + } + return last; +} + // ============================================================================ // Directory reading with sorting and file sizes // ============================================================================ @@ -100,6 +202,55 @@ static void filemanager_read_drives(FileManagerState* fm) { fm->at_drives_root = true; fm->current_path[0] = '\0'; + // Home folder entry (if we have a valid home directory) + DesktopState* ds = fm->desktop; + if (ds && ds->home_dir[0] != '\0') { + int i = fm->entry_count; + montauk::strncpy(fm->entry_names[i], "Home", 63); + fm->entry_types[i] = 4; // home + fm->entry_sizes[i] = 0; + fm->is_dir[i] = true; + fm->drive_indices[i] = -1; + fm->entry_count++; + } + + // Apps entry + { + int i = fm->entry_count; + montauk::strncpy(fm->entry_names[i], "Apps", 63); + fm->entry_types[i] = 5; // apps + fm->entry_sizes[i] = 0; + fm->is_dir[i] = true; + fm->drive_indices[i] = -1; + fm->entry_count++; + } + + // Special user folders (Documents, Desktop, Music, etc.) - only if they exist + if (ds && ds->home_dir[0] != '\0') { + for (int sf = 0; sf < SF_COUNT && fm->entry_count < 64; sf++) { + char probe_path[256]; + montauk::strcpy(probe_path, ds->home_dir); + int plen = montauk::slen(probe_path); + if (plen > 0 && probe_path[plen - 1] != '/') + str_append(probe_path, "/", 256); + str_append(probe_path, sf_names[sf], 256); + + // Probe: try open to check if the directory exists + int probe_fd = montauk::open(probe_path); + if (probe_fd >= 0) { + montauk::close(probe_fd); + int i = fm->entry_count; + montauk::strncpy(fm->entry_names[i], sf_names[sf], 63); + fm->entry_types[i] = 7; // special_dir + fm->entry_sizes[i] = 0; + fm->is_dir[i] = true; + fm->drive_indices[i] = sf; // special folder index + fm->entry_count++; + } + } + } + + // Drive entries int drives[FM_MAX_DRIVES]; int driveCount = montauk::drivelist(drives, FM_MAX_DRIVES); @@ -140,6 +291,10 @@ static void filemanager_read_drives(FileManagerState* fm) { static void filemanager_read_dir(FileManagerState* fm) { fm->at_drives_root = false; + if (fm->at_apps_view) { + fm->at_apps_view = false; + filemanager_free_app_icons(fm); + } const char* names[64]; fm->entry_count = montauk::readdir(fm->current_path, names, 64); if (fm->entry_count < 0) fm->entry_count = 0; @@ -244,6 +399,113 @@ static void filemanager_read_dir(FileManagerState* fm) { fm->last_click_time = 0; } +// ============================================================================ +// Apps view population +// ============================================================================ + +static void filemanager_free_app_icons(FileManagerState* fm) { + for (int i = 0; i < fm->app_icon_count; i++) { + if (fm->app_icons_lg[i].pixels) { + montauk::mfree(fm->app_icons_lg[i].pixels); + fm->app_icons_lg[i].pixels = nullptr; + } + if (fm->app_icons_sm[i].pixels) { + montauk::mfree(fm->app_icons_sm[i].pixels); + fm->app_icons_sm[i].pixels = nullptr; + } + } + fm->app_icon_count = 0; +} + +static void filemanager_read_apps(FileManagerState* fm) { + filemanager_free_app_icons(fm); + + fm->at_drives_root = false; + fm->at_apps_view = true; + fm->entry_count = 0; + + DesktopState* ds = fm->desktop; + if (!ds) return; + + // Scan manifests directly (like desktop_scan_apps but load icons at FM sizes) + montauk::fmkdir("0:/apps"); + const char* entries[32]; + int count = montauk::readdir("0:/apps", entries, 32); + + // Extract basenames from readdir results (strip "apps/" prefix) + for (int i = 0; i < count && fm->entry_count < 16; i++) { + const char* raw = entries[i]; + // Strip "apps/" prefix + if (raw[0] == 'a' && raw[1] == 'p' && raw[2] == 'p' && raw[3] == 's' && raw[4] == '/') + raw += 5; + char dirname[64]; + montauk::strncpy(dirname, raw, 63); + int dlen = montauk::slen(dirname); + if (dlen > 0 && dirname[dlen - 1] == '/') dirname[dlen - 1] = '\0'; + if (dirname[0] == '\0') continue; + + // Open manifest + char manifest_path[128]; + snprintf(manifest_path, 128, "0:/apps/%s/manifest.toml", dirname); + int fh = montauk::open(manifest_path); + if (fh < 0) continue; + + uint64_t sz = montauk::getsize(fh); + if (sz == 0 || sz > 4096) { montauk::close(fh); continue; } + + char* text = (char*)montauk::malloc(sz + 1); + montauk::read(fh, (uint8_t*)text, 0, sz); + montauk::close(fh); + text[sz] = '\0'; + + auto doc = montauk::toml::parse(text); + montauk::mfree(text); + + const char* name = doc.get_string("app.name", "Unknown"); + const char* binary = doc.get_string("app.binary", ""); + const char* icon_file = doc.get_string("app.icon", ""); + + int idx = fm->entry_count; + montauk::strncpy(fm->entry_names[idx], name, 63); + fm->entry_types[idx] = 6; // app entry + fm->entry_sizes[idx] = 0; + fm->is_dir[idx] = false; + + // Store binary path in drive_indices as an app_map index + fm->app_map[idx] = -1; + // Find matching external_app by binary path + char bin_path[128]; + snprintf(bin_path, 128, "0:/apps/%s/%s", dirname, binary); + for (int x = 0; x < ds->external_app_count; x++) { + if (montauk::streq(ds->external_apps[x].binary_path, bin_path)) { + fm->app_map[idx] = x; + break; + } + } + + // Load icons at file manager sizes + fm->app_icons_lg[idx] = {}; + fm->app_icons_sm[idx] = {}; + if (icon_file[0]) { + char icon_path[128]; + snprintf(icon_path, 128, "0:/apps/%s/%s", dirname, icon_file); + Color defColor = colors::ICON_COLOR; + fm->app_icons_lg[idx] = svg_load(icon_path, 48, 48, defColor); + fm->app_icons_sm[idx] = svg_load(icon_path, 16, 16, defColor); + } + + doc.destroy(); + fm->entry_count++; + fm->app_icon_count = fm->entry_count; + } + + fm->selected = -1; + fm->scroll_offset = 0; + fm->scrollbar.scroll_offset = 0; + fm->last_click_item = -1; + fm->last_click_time = 0; +} + // ============================================================================ // Recursive directory deletion // ============================================================================ @@ -252,7 +514,7 @@ static bool filemanager_delete_recursive(const char* path) { // Try deleting as a file (or empty directory) first if (montauk::fdelete(path) == 0) return true; - // If that failed, it may be a non-empty directory — enumerate and delete children + // If that failed, it may be a non-empty directory -- enumerate and delete children const char* names[64]; int count = montauk::readdir(path, names, 64); if (count < 0) return false; @@ -300,10 +562,298 @@ static bool filemanager_delete_recursive(const char* path) { filemanager_delete_recursive(child); } - // Now the directory should be empty — delete it + // Now the directory should be empty -- delete it return montauk::fdelete(path) == 0; } +// ============================================================================ +// File copy helper (single file) +// ============================================================================ + +static bool filemanager_copy_file(const char* src, const char* dst) { + int sfd = montauk::open(src); + if (sfd < 0) return false; + int size = (int)montauk::getsize(sfd); + + // Create destination + int dfd = montauk::fcreate(dst); + if (dfd < 0) { + montauk::close(sfd); + return false; + } + + if (size > 0) { + // Cap at 4 MB to avoid exhausting memory + if (size > 4 * 1024 * 1024) { + montauk::close(sfd); + montauk::close(dfd); + montauk::fdelete(dst); + return false; + } + uint8_t* buf = (uint8_t*)montauk::malloc(size); + if (!buf) { + montauk::close(sfd); + montauk::close(dfd); + montauk::fdelete(dst); + return false; + } + montauk::read(sfd, buf, 0, size); + montauk::fwrite(dfd, buf, 0, size); + montauk::mfree(buf); + } + + montauk::close(sfd); + montauk::close(dfd); + return true; +} + +// Recursive directory copy +static bool filemanager_copy_dir_recursive(const char* src, const char* dst) { + montauk::fmkdir(dst); + + const char* names[64]; + int count = montauk::readdir(src, names, 64); + if (count < 0) return false; + + // Compute prefix to strip + const char* after_drive = src; + for (int k = 0; after_drive[k]; k++) { + if (after_drive[k] == ':' && after_drive[k + 1] == '/') { + after_drive += k + 2; + break; + } + } + char prefix[256] = {0}; + int prefix_len = 0; + if (after_drive[0] != '\0') { + montauk::strcpy(prefix, after_drive); + prefix_len = montauk::slen(prefix); + if (prefix_len > 0 && prefix[prefix_len - 1] != '/') { + prefix[prefix_len++] = '/'; + prefix[prefix_len] = '\0'; + } + } + + for (int i = 0; i < count; i++) { + const char* raw = names[i]; + if (prefix_len > 0) { + bool match = true; + for (int k = 0; k < prefix_len; k++) { + if (raw[k] != prefix[k]) { match = false; break; } + } + if (match) raw += prefix_len; + } + + bool child_is_dir = false; + char basename[64]; + montauk::strncpy(basename, raw, 63); + int blen = montauk::slen(basename); + if (blen > 0 && basename[blen - 1] == '/') { + child_is_dir = true; + basename[blen - 1] = '\0'; + } + + char src_child[512], dst_child[512]; + filemanager_build_fullpath(src_child, 512, src, basename); + filemanager_build_fullpath(dst_child, 512, dst, basename); + + if (child_is_dir) + filemanager_copy_dir_recursive(src_child, dst_child); + else + filemanager_copy_file(src_child, dst_child); + } + + return true; +} + +// ============================================================================ +// Clipboard operations +// ============================================================================ + +static void filemanager_do_copy(FileManagerState* fm) { + if (fm->selected < 0 || fm->selected >= fm->entry_count) return; + if (fm->at_drives_root || fm->entry_types[fm->selected] == 3) return; + + filemanager_build_fullpath(fm->clipboard_path, 256, + fm->current_path, fm->entry_names[fm->selected]); + fm->clipboard_has_data = true; + fm->clipboard_is_cut = false; +} + +static void filemanager_do_cut(FileManagerState* fm) { + if (fm->selected < 0 || fm->selected >= fm->entry_count) return; + if (fm->at_drives_root || fm->entry_types[fm->selected] == 3) return; + + filemanager_build_fullpath(fm->clipboard_path, 256, + fm->current_path, fm->entry_names[fm->selected]); + fm->clipboard_has_data = true; + fm->clipboard_is_cut = true; +} + +static void filemanager_do_paste(FileManagerState* fm) { + if (!fm->clipboard_has_data || fm->at_drives_root) return; + + const char* basename = path_basename(fm->clipboard_path); + char dst[512]; + filemanager_build_fullpath(dst, 512, fm->current_path, basename); + + // Check if source is a directory by trying to readdir it + const char* probe[1]; + int probe_count = montauk::readdir(fm->clipboard_path, probe, 1); + bool src_is_dir = (probe_count >= 0); + + bool ok; + if (src_is_dir) + ok = filemanager_copy_dir_recursive(fm->clipboard_path, dst); + else + ok = filemanager_copy_file(fm->clipboard_path, dst); + + if (ok && fm->clipboard_is_cut) { + if (src_is_dir) + filemanager_delete_recursive(fm->clipboard_path); + else + montauk::fdelete(fm->clipboard_path); + fm->clipboard_has_data = false; + } + + filemanager_read_dir(fm); +} + +// ============================================================================ +// Rename operations +// ============================================================================ + +static void filemanager_start_rename(FileManagerState* fm) { + if (fm->selected < 0 || fm->selected >= fm->entry_count) return; + if (fm->at_drives_root || fm->entry_types[fm->selected] == 3) return; + + fm->rename_active = true; + fm->rename_idx = fm->selected; + montauk::strcpy(fm->rename_buf, fm->entry_names[fm->selected]); + fm->rename_len = montauk::slen(fm->rename_buf); + fm->rename_cursor = fm->rename_len; +} + +static void filemanager_finish_rename(FileManagerState* fm) { + if (!fm->rename_active) return; + fm->rename_active = false; + + // If name unchanged, skip + if (montauk::streq(fm->rename_buf, fm->entry_names[fm->rename_idx])) return; + if (fm->rename_len == 0) return; + + char old_path[512], new_path[512]; + filemanager_build_fullpath(old_path, 512, + fm->current_path, fm->entry_names[fm->rename_idx]); + filemanager_build_fullpath(new_path, 512, + fm->current_path, fm->rename_buf); + + if (fm->is_dir[fm->rename_idx]) { + // Directory rename: copy recursively then delete old + if (filemanager_copy_dir_recursive(old_path, new_path)) + filemanager_delete_recursive(old_path); + } else { + // File rename: copy then delete old + if (filemanager_copy_file(old_path, new_path)) + montauk::fdelete(old_path); + } + + filemanager_read_dir(fm); +} + +static void filemanager_cancel_rename(FileManagerState* fm) { + fm->rename_active = false; +} + +// ============================================================================ +// New folder +// ============================================================================ + +static void filemanager_new_folder(FileManagerState* fm) { + if (fm->at_drives_root) return; + + // Find a unique name + char name[64] = "New Folder"; + char path[512]; + filemanager_build_fullpath(path, 512, fm->current_path, name); + int attempt = 1; + // Try creating; if it fails, append a number + if (montauk::fmkdir(path) != 0) { + for (attempt = 2; attempt <= 99; attempt++) { + snprintf(name, 64, "New Folder %d", attempt); + filemanager_build_fullpath(path, 512, fm->current_path, name); + if (montauk::fmkdir(path) == 0) break; + } + } + + filemanager_read_dir(fm); + + // Select the new folder and start rename + for (int i = 0; i < fm->entry_count; i++) { + if (montauk::streq(fm->entry_names[i], name)) { + fm->selected = i; + filemanager_start_rename(fm); + break; + } + } +} + +// ============================================================================ +// Delete selected entry +// ============================================================================ + +static void filemanager_delete_selected(FileManagerState* fm) { + if (fm->selected < 0 || fm->selected >= fm->entry_count) return; + if (fm->at_drives_root || fm->entry_types[fm->selected] == 3) return; + + char fullpath[512]; + filemanager_build_fullpath(fullpath, 512, + fm->current_path, fm->entry_names[fm->selected]); + if (fm->is_dir[fm->selected]) + filemanager_delete_recursive(fullpath); + else + montauk::fdelete(fullpath); + filemanager_read_dir(fm); +} + +// ============================================================================ +// Context menu +// ============================================================================ + +static void filemanager_open_ctx_menu(FileManagerState* fm, int local_x, int local_y, + int target_idx) { + fm->ctx_open = true; + fm->ctx_x = local_x; + fm->ctx_y = local_y; + fm->ctx_target_idx = target_idx; + fm->ctx_hover = -1; + fm->ctx_item_count = 0; + + if (target_idx >= 0 && target_idx < fm->entry_count) { + int tt = fm->entry_types[target_idx]; + if ((fm->at_drives_root && (tt == 3 || tt == 4 || tt == 5 || tt == 7)) || + (fm->at_apps_view && tt == 6)) { + // Drive, Home, Apps shortcut, or app entry: only Open + fm->ctx_items[fm->ctx_item_count++] = CTX_OPEN; + } else { + fm->ctx_items[fm->ctx_item_count++] = CTX_OPEN; + fm->ctx_items[fm->ctx_item_count++] = CTX_COPY; + fm->ctx_items[fm->ctx_item_count++] = CTX_CUT; + fm->ctx_items[fm->ctx_item_count++] = CTX_RENAME; + fm->ctx_items[fm->ctx_item_count++] = CTX_DELETE; + } + } else { + // Background click + if (fm->clipboard_has_data) + fm->ctx_items[fm->ctx_item_count++] = CTX_PASTE; + fm->ctx_items[fm->ctx_item_count++] = CTX_NEW_FOLDER; + } +} + +static void filemanager_close_ctx_menu(FileManagerState* fm) { + fm->ctx_open = false; +} + // ============================================================================ // History management // ============================================================================ @@ -332,9 +882,18 @@ static void filemanager_navigate(FileManagerState* fm, const char* name) { static void filemanager_go_up(FileManagerState* fm) { if (fm->at_drives_root) return; + // From apps view, go back to Computer + if (fm->at_apps_view) { + fm->at_apps_view = false; + filemanager_free_app_icons(fm); + filemanager_read_drives(fm); + filemanager_push_history(fm); + return; + } + int len = montauk::slen(fm->current_path); - // At drive root (e.g. "0:/" or "10:/") — go to drives view + // At drive root (e.g. "0:/" or "10:/") -- go to drives view bool is_drive_root = false; if (len >= 3 && fm->current_path[len - 1] == '/') { // Check if path is just "N:/" or "NN:/" @@ -393,10 +952,135 @@ static void filemanager_go_forward(FileManagerState* fm) { } static void filemanager_go_home(FileManagerState* fm) { + if (fm->at_apps_view) { + fm->at_apps_view = false; + filemanager_free_app_icons(fm); + } filemanager_read_drives(fm); filemanager_push_history(fm); } +// ============================================================================ +// Path bar editing +// ============================================================================ + +static void filemanager_start_pathbar(FileManagerState* fm) { + fm->pathbar_editing = true; + if (fm->at_drives_root) { + fm->pathbar_buf[0] = '\0'; + fm->pathbar_len = 0; + } else { + montauk::strcpy(fm->pathbar_buf, fm->current_path); + fm->pathbar_len = montauk::slen(fm->pathbar_buf); + } + fm->pathbar_cursor = fm->pathbar_len; +} + +static void filemanager_cancel_pathbar(FileManagerState* fm) { + fm->pathbar_editing = false; +} + +static void filemanager_commit_pathbar(FileManagerState* fm) { + fm->pathbar_editing = false; + if (fm->pathbar_len == 0) { + filemanager_read_drives(fm); + filemanager_push_history(fm); + return; + } + montauk::strcpy(fm->current_path, fm->pathbar_buf); + filemanager_push_history(fm); + filemanager_read_dir(fm); +} + +// ============================================================================ +// Open file/directory/drive +// ============================================================================ + +static void filemanager_open_entry(FileManagerState* fm, int idx) { + if (idx < 0 || idx >= fm->entry_count) return; + + // Special user folder in Computer view + if (fm->at_drives_root && fm->entry_types[idx] == 7) { + DesktopState* ds = fm->desktop; + if (ds && ds->home_dir[0] != '\0') { + montauk::strcpy(fm->current_path, ds->home_dir); + int plen = montauk::slen(fm->current_path); + if (plen > 0 && fm->current_path[plen - 1] != '/') + str_append(fm->current_path, "/", 256); + str_append(fm->current_path, fm->entry_names[idx], 256); + filemanager_push_history(fm); + filemanager_read_dir(fm); + } + return; + } + + // Apps shortcut in Computer view + if (fm->at_drives_root && fm->entry_types[idx] == 5) { + filemanager_read_apps(fm); + return; + } + + // App entry in apps view - launch it + if (fm->at_apps_view && fm->entry_types[idx] == 6) { + DesktopState* ds = fm->desktop; + if (ds && fm->app_map[idx] >= 0 && fm->app_map[idx] < ds->external_app_count) { + montauk::spawn(ds->external_apps[fm->app_map[idx]].binary_path, ds->home_dir); + } + return; + } + + if (fm->at_drives_root && fm->entry_types[idx] == 4) { + // Home folder + DesktopState* ds = fm->desktop; + if (ds && ds->home_dir[0] != '\0') { + montauk::strcpy(fm->current_path, ds->home_dir); + filemanager_push_history(fm); + filemanager_read_dir(fm); + } + return; + } + + if (fm->at_drives_root && fm->entry_types[idx] == 3) { + int d = fm->drive_indices[idx]; + char dpath[8]; + if (d < 10) { + dpath[0] = '0' + d; dpath[1] = ':'; dpath[2] = '/'; dpath[3] = '\0'; + } else { + dpath[0] = '1'; dpath[1] = '0' + (d - 10); dpath[2] = ':'; dpath[3] = '/'; dpath[4] = '\0'; + } + montauk::strcpy(fm->current_path, dpath); + filemanager_push_history(fm); + filemanager_read_dir(fm); + return; + } + + if (fm->is_dir[idx]) { + filemanager_navigate(fm, fm->entry_names[idx]); + return; + } + + // Open file with appropriate app + char fullpath[512]; + filemanager_build_fullpath(fullpath, 512, fm->current_path, fm->entry_names[idx]); + if (is_image_file(fm->entry_names[idx])) { + montauk::spawn("0:/apps/imageviewer/imageviewer.elf", fullpath); + } else if (is_font_file(fm->entry_names[idx])) { + montauk::spawn("0:/apps/fontpreview/fontpreview.elf", fullpath); + } else if (is_pdf_file(fm->entry_names[idx])) { + montauk::spawn("0:/apps/pdfviewer/pdfviewer.elf", fullpath); + } else if (is_spreadsheet_file(fm->entry_names[idx])) { + montauk::spawn("0:/apps/spreadsheet/spreadsheet.elf", fullpath); + } else if (is_video_file(fm->entry_names[idx])) { + montauk::spawn("0:/apps/video/video.elf", fullpath); + } else if (is_audio_file(fm->entry_names[idx])) { + montauk::spawn("0:/apps/music/music.elf", fullpath); + } else if (str_ends_with(fm->entry_names[idx], ".elf")) { + montauk::spawn(fullpath); + } else if (fm->desktop) { + open_texteditor_with_file(fm->desktop, fullpath); + } +} + // ============================================================================ // Drawing // ============================================================================ @@ -408,8 +1092,9 @@ static void filemanager_draw_header(Canvas& c, FileManagerState* fm, // ---- Toolbar (32px) ---- c.fill_rect(0, 0, c.w, FM_TOOLBAR_H, toolbar_color); + // Navigation buttons: Back, Forward, Up, Home struct ToolBtn { int x; SvgIcon* icon; }; - ToolBtn btns[4] = { + ToolBtn nav_btns[4] = { { 4, ds ? &ds->icon_go_back : nullptr }, { 32, ds ? &ds->icon_go_forward : nullptr }, { 60, ds ? &ds->icon_go_up : nullptr }, @@ -417,18 +1102,17 @@ static void filemanager_draw_header(Canvas& c, FileManagerState* fm, }; for (int i = 0; i < 4; i++) { - int bx = btns[i].x; + int bx = nav_btns[i].x; int by = 4; c.fill_rect(bx, by, 24, 24, btn_bg); - - if (btns[i].icon) { - int ix = bx + (24 - btns[i].icon->width) / 2; - int iy = by + (24 - btns[i].icon->height) / 2; - c.icon(ix, iy, *btns[i].icon); + if (nav_btns[i].icon) { + int ix = bx + (24 - nav_btns[i].icon->width) / 2; + int iy = by + (24 - nav_btns[i].icon->height) / 2; + c.icon(ix, iy, *nav_btns[i].icon); } } - // Toggle view button (5th toolbar button) + // View toggle button { int bx = 120, by = 4; c.fill_rect(bx, by, 24, 24, btn_bg); @@ -442,18 +1126,35 @@ static void filemanager_draw_header(Canvas& c, FileManagerState* fm, } } - // Delete button (6th toolbar button) — active when a file or directory is selected - { - int bx = 148, by = 4; - bool has_sel = fm->selected >= 0 && fm->selected < fm->entry_count - && !fm->at_drives_root - && fm->entry_types[fm->selected] != 3; - Color del_bg = has_sel ? btn_bg : Color::from_rgb(0xF0, 0xF0, 0xF0); - c.fill_rect(bx, by, 24, 24, del_bg); - if (ds && ds->icon_delete.pixels) { - int ix = bx + (24 - ds->icon_delete.width) / 2; - int iy = by + (24 - ds->icon_delete.height) / 2; - c.icon(ix, iy, ds->icon_delete); + // Separator line between nav group and action group + c.vline(152, 6, 20, colors::BORDER); + + // Action buttons: Copy, Cut, Paste, Rename, New Folder, Delete + bool has_sel = fm->selected >= 0 && fm->selected < fm->entry_count + && !fm->at_drives_root && !fm->at_apps_view + && fm->entry_types[fm->selected] != 3; + bool has_clip = fm->clipboard_has_data && !fm->at_drives_root && !fm->at_apps_view; + Color dim_bg = Color::from_rgb(0xF0, 0xF0, 0xF0); + + // Icon toolbar buttons: Copy, Cut, Paste, Rename, New Folder, Delete + struct ActionBtn { int x; SvgIcon* icon; bool enabled; }; + ActionBtn action_btns[] = { + { 160, ds ? &ds->icon_copy : nullptr, has_sel }, + { 188, ds ? &ds->icon_cut : nullptr, has_sel }, + { 216, ds ? &ds->icon_paste : nullptr, has_clip }, + { 244, ds ? &ds->icon_rename : nullptr, has_sel }, + { 272, ds ? &ds->icon_folder_new : nullptr, !fm->at_drives_root && !fm->at_apps_view }, + { 300, ds ? &ds->icon_delete : nullptr, has_sel }, + }; + + for (int i = 0; i < 6; i++) { + int bx = action_btns[i].x; + int by = 4; + c.fill_rect(bx, by, 24, 24, action_btns[i].enabled ? btn_bg : dim_bg); + if (action_btns[i].icon && action_btns[i].icon->pixels) { + int ix = bx + (24 - action_btns[i].icon->width) / 2; + int iy = by + (24 - action_btns[i].icon->height) / 2; + c.icon(ix, iy, *action_btns[i].icon); } } @@ -462,8 +1163,28 @@ static void filemanager_draw_header(Canvas& c, FileManagerState* fm, // ---- Path bar ---- int pathbar_y = FM_TOOLBAR_H; - c.fill_rect(0, pathbar_y, c.w, FM_PATHBAR_H, Color::from_rgb(0xF0, 0xF0, 0xF0)); - c.text(8, pathbar_y + 4, fm->at_drives_root ? "Drives" : fm->current_path, colors::TEXT_COLOR); + if (fm->pathbar_editing) { + // Editable text input + c.fill_rect(0, pathbar_y, c.w, FM_PATHBAR_H, colors::WHITE); + c.rect(0, pathbar_y, c.w, FM_PATHBAR_H, colors::ACCENT); + int fh = system_font_height(); + int ty = pathbar_y + (FM_PATHBAR_H - fh) / 2; + c.text(8, ty, fm->pathbar_buf, colors::TEXT_COLOR); + // Cursor + char prefix[256]; + int cpos = fm->pathbar_cursor; + if (cpos > 255) cpos = 255; + for (int k = 0; k < cpos; k++) prefix[k] = fm->pathbar_buf[k]; + prefix[cpos] = '\0'; + int cx = 8 + text_width(prefix); + c.vline(cx, ty, fh, colors::ACCENT); + } else { + c.fill_rect(0, pathbar_y, c.w, FM_PATHBAR_H, Color::from_rgb(0xF0, 0xF0, 0xF0)); + const char* pathbar_text = fm->current_path; + if (fm->at_drives_root) pathbar_text = "Computer"; + else if (fm->at_apps_view) pathbar_text = "Apps"; + c.text(8, pathbar_y + 4, pathbar_text, colors::TEXT_COLOR); + } // Path bar separator c.hline(0, pathbar_y + FM_PATHBAR_H - 1, c.w, colors::BORDER); @@ -519,7 +1240,20 @@ static void filemanager_on_draw(Window* win, Framebuffer& fb) { // Large icon centered horizontally int icon_x = cell_x + (FM_GRID_CELL_W - FM_GRID_ICON) / 2; int icon_y = cell_y + FM_GRID_PAD; - if (ds && fm->entry_types[i] == 3 && ds->icon_drive_lg.pixels) { + // Check for special folder icon (type 7 in Computer, or type 1 dir with matching name) + int sfi = -1; + if (fm->entry_types[i] == 7) sfi = fm->drive_indices[i]; + else if (ds && fm->entry_types[i] == 1) sfi = special_folder_index(fm->entry_names[i]); + + if (sfi >= 0 && ds && ds->icon_special_folder_lg[sfi].pixels) { + c.icon(icon_x, icon_y, ds->icon_special_folder_lg[sfi]); + } else if (fm->entry_types[i] == 6 && i < fm->app_icon_count && fm->app_icons_lg[i].pixels) { + c.icon(icon_x, icon_y, fm->app_icons_lg[i]); + } else if (ds && fm->entry_types[i] == 5 && ds->icon_apps_lg.pixels) { + c.icon(icon_x, icon_y, ds->icon_apps_lg); + } else if (ds && fm->entry_types[i] == 4 && ds->icon_home_folder_lg.pixels) { + c.icon(icon_x, icon_y, ds->icon_home_folder_lg); + } else if (ds && fm->entry_types[i] == 3 && ds->icon_drive_lg.pixels) { c.icon(icon_x, icon_y, ds->icon_drive_lg); } else if (ds && fm->entry_types[i] == 1 && ds->icon_folder_lg.pixels) { c.icon(icon_x, icon_y, ds->icon_folder_lg); @@ -538,22 +1272,46 @@ static void filemanager_on_draw(Window* win, Framebuffer& fb) { } // Filename centered below icon, truncated if needed - char label[16]; - int nlen = montauk::slen(fm->entry_names[i]); - if (nlen > 9) { - for (int k = 0; k < 9; k++) label[k] = fm->entry_names[i][k]; - label[9] = '.'; - label[10] = '.'; - label[11] = '\0'; + // If renaming this entry, draw the rename textbox instead + if (fm->rename_active && fm->rename_idx == i) { + int ty = icon_y + FM_GRID_ICON + 2; + int tw = FM_GRID_CELL_W - 4; + if (ty >= list_y && ty + system_font_height() + 4 <= c.h) { + c.fill_rect(cell_x + 2, ty - 1, tw, system_font_height() + 2, colors::WHITE); + c.rect(cell_x + 2, ty - 1, tw, system_font_height() + 2, colors::ACCENT); + // Draw rename text (truncated to cell width) + char display[16]; + int rlen = fm->rename_len; + if (rlen > 10) rlen = 10; + for (int k = 0; k < rlen; k++) display[k] = fm->rename_buf[k]; + display[rlen] = '\0'; + c.text(cell_x + 4, ty, display, colors::TEXT_COLOR); + // Cursor + char prefix[64]; + int cpos = fm->rename_cursor < rlen ? fm->rename_cursor : rlen; + for (int k = 0; k < cpos; k++) prefix[k] = fm->rename_buf[k]; + prefix[cpos] = '\0'; + int cx = cell_x + 4 + text_width(prefix); + c.vline(cx, ty, system_font_height(), colors::ACCENT); + } } else { - montauk::strncpy(label, fm->entry_names[i], 15); + char label[16]; + int nlen = montauk::slen(fm->entry_names[i]); + if (nlen > 9) { + for (int k = 0; k < 9; k++) label[k] = fm->entry_names[i][k]; + label[9] = '.'; + label[10] = '.'; + label[11] = '\0'; + } else { + montauk::strncpy(label, fm->entry_names[i], 15); + } + int tw = text_width(label); + int tx = cell_x + (FM_GRID_CELL_W - tw) / 2; + if (tx < cell_x) tx = cell_x; + int ty = icon_y + FM_GRID_ICON + 2; + if (ty >= list_y && ty + system_font_height() <= c.h) + c.text(tx, ty, label, colors::TEXT_COLOR); } - int tw = text_width(label); - int tx = cell_x + (FM_GRID_CELL_W - tw) / 2; - if (tx < cell_x) tx = cell_x; - int ty = icon_y + FM_GRID_ICON + 2; - if (ty >= list_y && ty + system_font_height() <= c.h) - c.text(tx, ty, label, colors::TEXT_COLOR); } } else { // ---- List View ---- @@ -605,10 +1363,24 @@ static void filemanager_on_draw(Window* win, Framebuffer& fb) { c.fill_rect(0, sy, c.w - FM_SCROLLBAR_W, sh, colors::MENU_HOVER); } - // Icon + // Icon (skip if it would bleed above the list area) int ico_x = 8; int ico_y = iy + (FM_ITEM_H - 16) / 2; - if (ds && fm->entry_types[i] == 3 && ds->icon_drive.pixels) { + // Check for special folder icon + int sfi_sm = -1; + if (fm->entry_types[i] == 7) sfi_sm = fm->drive_indices[i]; + else if (ds && fm->entry_types[i] == 1) sfi_sm = special_folder_index(fm->entry_names[i]); + + if (ico_y < list_y) { /* clipped by header repaint */ } + else if (sfi_sm >= 0 && ds && ds->icon_special_folder[sfi_sm].pixels) { + c.icon(ico_x, ico_y, ds->icon_special_folder[sfi_sm]); + } else if (fm->entry_types[i] == 6 && i < fm->app_icon_count && fm->app_icons_sm[i].pixels) { + c.icon(ico_x, ico_y, fm->app_icons_sm[i]); + } else if (ds && fm->entry_types[i] == 5 && ds->icon_apps.pixels) { + c.icon(ico_x, ico_y, ds->icon_apps); + } else if (ds && fm->entry_types[i] == 4 && ds->icon_home_folder.pixels) { + c.icon(ico_x, ico_y, ds->icon_home_folder); + } else if (ds && fm->entry_types[i] == 3 && ds->icon_drive.pixels) { c.icon(ico_x, ico_y, ds->icon_drive); } else if (ds && fm->entry_types[i] == 1 && ds->icon_folder.pixels) { c.icon(ico_x, ico_y, ds->icon_folder); @@ -626,12 +1398,29 @@ static void filemanager_on_draw(Window* win, Framebuffer& fb) { c.fill_rect(ico_x, iy_clip, 16, ih_clip, icon_c); } - // Name + // Name (or rename textbox) int tx = 30; int fm_sfh = system_font_height(); int ty = iy + (FM_ITEM_H - fm_sfh) / 2; - if (ty >= list_y && ty + fm_sfh <= c.h) - c.text(tx, ty, fm->entry_names[i], colors::TEXT_COLOR); + + if (fm->rename_active && fm->rename_idx == i && ty >= list_y && ty + fm_sfh <= c.h) { + // Rename textbox inline + int rw = (size_col_x > 100 ? size_col_x - 8 : c.w - FM_SCROLLBAR_W - 8) - tx; + c.fill_rect(tx - 2, ty - 1, rw, fm_sfh + 2, colors::WHITE); + c.rect(tx - 2, ty - 1, rw, fm_sfh + 2, colors::ACCENT); + c.text(tx, ty, fm->rename_buf, colors::TEXT_COLOR); + // Cursor + char prefix[64]; + int cpos = fm->rename_cursor; + if (cpos > 63) cpos = 63; + for (int k = 0; k < cpos; k++) prefix[k] = fm->rename_buf[k]; + prefix[cpos] = '\0'; + int cx = tx + text_width(prefix); + c.vline(cx, ty, fm_sfh, colors::ACCENT); + } else { + if (ty >= list_y && ty + fm_sfh <= c.h) + c.text(tx, ty, fm->entry_names[i], colors::TEXT_COLOR); + } // Size if (size_col_x > 100 && !fm->is_dir[i] && ty >= list_y && ty + fm_sfh <= c.h) { @@ -643,7 +1432,10 @@ static void filemanager_on_draw(Window* win, Framebuffer& fb) { // Type if (type_col_x > 160 && ty >= list_y && ty + fm_sfh <= c.h) { const char* type_str = "File"; - if (fm->entry_types[i] == 3) type_str = "Drive"; + if (fm->entry_types[i] == 6) type_str = "App"; + else if (fm->entry_types[i] == 5) type_str = "Apps"; + else if (fm->entry_types[i] == 4) type_str = "Home"; + else if (fm->entry_types[i] == 3) type_str = "Drive"; else if (fm->entry_types[i] == 1) type_str = "Dir"; else if (fm->entry_types[i] == 2) type_str = "Exec"; c.text(type_col_x, ty, type_str, dim); @@ -671,6 +1463,37 @@ static void filemanager_on_draw(Window* win, Framebuffer& fb) { // Repaint header on top of content to clip scrolled icon overflow if (fm->scrollbar.scroll_offset > 0) filemanager_draw_header(c, fm, toolbar_color, btn_bg); + + // ---- Context menu overlay ---- + if (fm->ctx_open && fm->ctx_item_count > 0) { + int cmx = fm->ctx_x; + int cmy = fm->ctx_y; + int cmh = fm->ctx_item_count * CTX_ITEM_H + 8; + + // Clamp to window bounds + if (cmx + CTX_MENU_W > c.w) cmx = c.w - CTX_MENU_W; + if (cmy + cmh > c.h) cmy = c.h - cmh; + if (cmx < 0) cmx = 0; + if (cmy < 0) cmy = 0; + + // Shadow + c.fill_rect(cmx + 2, cmy + 2, CTX_MENU_W, cmh, Color::from_rgb(0x80, 0x80, 0x80)); + // Background + c.fill_rounded_rect(cmx, cmy, CTX_MENU_W, cmh, 4, colors::WHITE); + c.rect(cmx, cmy, CTX_MENU_W, cmh, colors::BORDER); + + for (int i = 0; i < fm->ctx_item_count; i++) { + int iy = cmy + 4 + i * CTX_ITEM_H; + + // Hover highlight + if (i == fm->ctx_hover) + c.fill_rect(cmx + 2, iy, CTX_MENU_W - 4, CTX_ITEM_H, colors::MENU_HOVER); + + int fh = system_font_height(); + int ty = iy + (CTX_ITEM_H - fh) / 2; + c.text(cmx + 12, ty, ctx_label(fm->ctx_items[i]), colors::TEXT_COLOR); + } + } } // ============================================================================ @@ -692,34 +1515,91 @@ static void filemanager_on_mouse(Window* win, MouseEvent& ev) { local_ev.y = local_y; fm->scrollbar.handle_mouse(local_ev); + // ---- Context menu interaction ---- + if (fm->ctx_open) { + int cmx = fm->ctx_x; + int cmy = fm->ctx_y; + int cmh = fm->ctx_item_count * CTX_ITEM_H + 8; + if (cmx + CTX_MENU_W > cw) cmx = cw - CTX_MENU_W; + if (cmy + cmh > win->content_h) cmy = win->content_h - cmh; + if (cmx < 0) cmx = 0; + if (cmy < 0) cmy = 0; + + // Update hover + if (local_x >= cmx && local_x < cmx + CTX_MENU_W && + local_y >= cmy + 4 && local_y < cmy + 4 + fm->ctx_item_count * CTX_ITEM_H) { + fm->ctx_hover = (local_y - cmy - 4) / CTX_ITEM_H; + } else { + fm->ctx_hover = -1; + } + + if (ev.left_pressed()) { + if (fm->ctx_hover >= 0 && fm->ctx_hover < fm->ctx_item_count) { + int action = fm->ctx_items[fm->ctx_hover]; + int target = fm->ctx_target_idx; + filemanager_close_ctx_menu(fm); + + // Select target if needed + if (target >= 0 && target < fm->entry_count) + fm->selected = target; + + switch (action) { + case CTX_OPEN: filemanager_open_entry(fm, target); break; + case CTX_COPY: filemanager_do_copy(fm); break; + case CTX_CUT: filemanager_do_cut(fm); break; + case CTX_PASTE: filemanager_do_paste(fm); break; + case CTX_RENAME: filemanager_start_rename(fm); break; + case CTX_DELETE: filemanager_delete_selected(fm); break; + case CTX_NEW_FOLDER: filemanager_new_folder(fm); break; + } + } else { + filemanager_close_ctx_menu(fm); + } + return; + } + if (ev.right_pressed()) { + filemanager_close_ctx_menu(fm); + return; + } + return; + } + + // ---- Cancel rename on click outside rename area ---- + if (fm->rename_active && ev.left_pressed()) { + filemanager_finish_rename(fm); + } + if (ev.left_pressed()) { + // Click on path bar area + if (local_y >= FM_TOOLBAR_H && local_y < FM_TOOLBAR_H + FM_PATHBAR_H) { + if (!fm->pathbar_editing) + filemanager_start_pathbar(fm); + return; + } + + // Clicking anywhere else while pathbar is editing commits the path + if (fm->pathbar_editing) { + filemanager_commit_pathbar(fm); + } + // Toolbar button clicks if (local_y < FM_TOOLBAR_H) { - if (local_x >= 4 && local_x < 28) filemanager_go_back(fm); - else if (local_x >= 32 && local_x < 56) filemanager_go_forward(fm); - else if (local_x >= 60 && local_x < 84) filemanager_go_up(fm); - else if (local_x >= 88 && local_x < 112) filemanager_go_home(fm); + // Navigation buttons + if (local_x >= 4 && local_x < 28) filemanager_go_back(fm); + else if (local_x >= 32 && local_x < 56) filemanager_go_forward(fm); + else if (local_x >= 60 && local_x < 84) filemanager_go_up(fm); + else if (local_x >= 88 && local_x < 112) filemanager_go_home(fm); else if (local_x >= 120 && local_x < 144) { fm->grid_view = !fm->grid_view; fm->scrollbar.scroll_offset = 0; } - else if (local_x >= 148 && local_x < 172) { - // Delete selected file or directory - if (fm->selected >= 0 && fm->selected < fm->entry_count - && !fm->at_drives_root && fm->entry_types[fm->selected] != 3) { - char fullpath[512]; - montauk::strcpy(fullpath, fm->current_path); - int plen = montauk::slen(fullpath); - if (plen > 0 && fullpath[plen - 1] != '/') - str_append(fullpath, "/", 512); - str_append(fullpath, fm->entry_names[fm->selected], 512); - if (fm->is_dir[fm->selected]) - filemanager_delete_recursive(fullpath); - else - montauk::fdelete(fullpath); - filemanager_read_dir(fm); - } - } + // Action buttons + else if (local_x >= 160 && local_x < 184) filemanager_do_copy(fm); + else if (local_x >= 188 && local_x < 212) filemanager_do_cut(fm); + else if (local_x >= 216 && local_x < 240) filemanager_do_paste(fm); + else if (local_x >= 244 && local_x < 268) filemanager_start_rename(fm); + else if (local_x >= 272 && local_x < 296) filemanager_new_folder(fm); + else if (local_x >= 300 && local_x < 324) filemanager_delete_selected(fm); return; } @@ -738,46 +1618,7 @@ static void filemanager_on_mouse(Window* win, MouseEvent& ev) { if (fm->last_click_item == clicked_idx && (now - fm->last_click_time) < 400) { - if (fm->at_drives_root && fm->entry_types[clicked_idx] == 3) { - // Navigate into drive - int d = fm->drive_indices[clicked_idx]; - char dpath[8]; - if (d < 10) { - dpath[0] = '0' + d; dpath[1] = ':'; dpath[2] = '/'; dpath[3] = '\0'; - } else { - dpath[0] = '1'; dpath[1] = '0' + (d - 10); dpath[2] = ':'; dpath[3] = '/'; dpath[4] = '\0'; - } - montauk::strcpy(fm->current_path, dpath); - filemanager_push_history(fm); - filemanager_read_dir(fm); - } else if (fm->is_dir[clicked_idx]) { - filemanager_navigate(fm, fm->entry_names[clicked_idx]); - } else { - char fullpath[512]; - montauk::strcpy(fullpath, fm->current_path); - int plen = montauk::slen(fullpath); - if (plen > 0 && fullpath[plen - 1] != '/') { - str_append(fullpath, "/", 512); - } - str_append(fullpath, fm->entry_names[clicked_idx], 512); - if (is_image_file(fm->entry_names[clicked_idx])) { - montauk::spawn("0:/apps/imageviewer/imageviewer.elf", fullpath); - } else if (is_font_file(fm->entry_names[clicked_idx])) { - montauk::spawn("0:/apps/fontpreview/fontpreview.elf", fullpath); - } else if (is_pdf_file(fm->entry_names[clicked_idx])) { - montauk::spawn("0:/apps/pdfviewer/pdfviewer.elf", fullpath); - } else if (is_spreadsheet_file(fm->entry_names[clicked_idx])) { - montauk::spawn("0:/apps/spreadsheet/spreadsheet.elf", fullpath); - } else if (is_video_file(fm->entry_names[clicked_idx])) { - montauk::spawn("0:/apps/video/video.elf", fullpath); - } else if (is_audio_file(fm->entry_names[clicked_idx])) { - montauk::spawn("0:/apps/music/music.elf", fullpath); - } else if (str_ends_with(fm->entry_names[clicked_idx], ".elf")) { - montauk::spawn(fullpath); - } else if (fm->desktop) { - open_texteditor_with_file(fm->desktop, fullpath); - } - } + filemanager_open_entry(fm, clicked_idx); fm->last_click_item = -1; fm->last_click_time = 0; } else { @@ -785,6 +1626,8 @@ static void filemanager_on_mouse(Window* win, MouseEvent& ev) { fm->last_click_item = clicked_idx; fm->last_click_time = now; } + } else { + fm->selected = -1; } } } else { @@ -800,46 +1643,7 @@ static void filemanager_on_mouse(Window* win, MouseEvent& ev) { // Double-click detection if (fm->last_click_item == clicked_idx && (now - fm->last_click_time) < 400) { - if (fm->at_drives_root && fm->entry_types[clicked_idx] == 3) { - int d = fm->drive_indices[clicked_idx]; - char dpath[8]; - if (d < 10) { - dpath[0] = '0' + d; dpath[1] = ':'; dpath[2] = '/'; dpath[3] = '\0'; - } else { - dpath[0] = '1'; dpath[1] = '0' + (d - 10); dpath[2] = ':'; dpath[3] = '/'; dpath[4] = '\0'; - } - montauk::strcpy(fm->current_path, dpath); - filemanager_push_history(fm); - filemanager_read_dir(fm); - } else if (fm->is_dir[clicked_idx]) { - filemanager_navigate(fm, fm->entry_names[clicked_idx]); - } else { - // Open file in appropriate viewer - char fullpath[512]; - montauk::strcpy(fullpath, fm->current_path); - int plen = montauk::slen(fullpath); - if (plen > 0 && fullpath[plen - 1] != '/') { - str_append(fullpath, "/", 512); - } - str_append(fullpath, fm->entry_names[clicked_idx], 512); - if (is_image_file(fm->entry_names[clicked_idx])) { - montauk::spawn("0:/apps/imageviewer/imageviewer.elf", fullpath); - } else if (is_font_file(fm->entry_names[clicked_idx])) { - montauk::spawn("0:/apps/fontpreview/fontpreview.elf", fullpath); - } else if (is_pdf_file(fm->entry_names[clicked_idx])) { - montauk::spawn("0:/apps/pdfviewer/pdfviewer.elf", fullpath); - } else if (is_spreadsheet_file(fm->entry_names[clicked_idx])) { - montauk::spawn("0:/apps/spreadsheet/spreadsheet.elf", fullpath); - } else if (is_video_file(fm->entry_names[clicked_idx])) { - montauk::spawn("0:/apps/video/video.elf", fullpath); - } else if (is_audio_file(fm->entry_names[clicked_idx])) { - montauk::spawn("0:/apps/music/music.elf", fullpath); - } else if (str_ends_with(fm->entry_names[clicked_idx], ".elf")) { - montauk::spawn(fullpath); - } else if (fm->desktop) { - open_texteditor_with_file(fm->desktop, fullpath); - } - } + filemanager_open_entry(fm, clicked_idx); fm->last_click_item = -1; fm->last_click_time = 0; } else { @@ -847,11 +1651,50 @@ static void filemanager_on_mouse(Window* win, MouseEvent& ev) { fm->last_click_item = clicked_idx; fm->last_click_time = now; } + } else { + fm->selected = -1; } } } } + // ---- Right-click: open context menu ---- + if (ev.right_pressed()) { + filemanager_cancel_rename(fm); + + // Determine what was right-clicked + int target_idx = -1; + + if (local_y >= FM_TOOLBAR_H + FM_PATHBAR_H) { + if (fm->grid_view) { + int list_y = FM_TOOLBAR_H + FM_PATHBAR_H; + if (local_x < cw - FM_SCROLLBAR_W) { + int cols = (cw - FM_SCROLLBAR_W) / FM_GRID_CELL_W; + if (cols < 1) cols = 1; + int col = local_x / FM_GRID_CELL_W; + int row = (local_y - list_y + fm->scrollbar.scroll_offset) / FM_GRID_CELL_H; + int idx = row * cols + col; + if (idx >= 0 && idx < fm->entry_count && col < cols) { + target_idx = idx; + fm->selected = idx; + } + } + } else { + int list_y = FM_TOOLBAR_H + FM_PATHBAR_H + FM_HEADER_H; + if (local_y >= list_y && local_x < cw - FM_SCROLLBAR_W) { + int rel_y = local_y - list_y + fm->scrollbar.scroll_offset; + int idx = rel_y / FM_ITEM_H; + if (idx >= 0 && idx < fm->entry_count) { + target_idx = idx; + fm->selected = idx; + } + } + } + } + + filemanager_open_ctx_menu(fm, local_x, local_y, target_idx); + } + // Scroll handling if (ev.scroll != 0) { int list_y_start = fm->grid_view @@ -875,13 +1718,131 @@ static void filemanager_on_key(Window* win, const Montauk::KeyEvent& key) { FileManagerState* fm = (FileManagerState*)win->app_data; if (!fm || !key.pressed) return; + // ---- Path bar editing key handling ---- + if (fm->pathbar_editing) { + if (key.ascii == '\n' || key.ascii == '\r') { + filemanager_commit_pathbar(fm); + } else if (key.scancode == 0x01) { + filemanager_cancel_pathbar(fm); + } else if (key.ascii == '\b' || key.scancode == 0x0E) { + if (fm->pathbar_cursor > 0) { + for (int i = fm->pathbar_cursor - 1; i < fm->pathbar_len - 1; i++) + fm->pathbar_buf[i] = fm->pathbar_buf[i + 1]; + fm->pathbar_len--; + fm->pathbar_cursor--; + fm->pathbar_buf[fm->pathbar_len] = '\0'; + } + } else if (key.scancode == 0x53) { + if (fm->pathbar_cursor < fm->pathbar_len) { + for (int i = fm->pathbar_cursor; i < fm->pathbar_len - 1; i++) + fm->pathbar_buf[i] = fm->pathbar_buf[i + 1]; + fm->pathbar_len--; + fm->pathbar_buf[fm->pathbar_len] = '\0'; + } + } else if (key.scancode == 0x4B) { + if (fm->pathbar_cursor > 0) fm->pathbar_cursor--; + } else if (key.scancode == 0x4D) { + if (fm->pathbar_cursor < fm->pathbar_len) fm->pathbar_cursor++; + } else if (key.scancode == 0x47) { + fm->pathbar_cursor = 0; + } else if (key.scancode == 0x4F) { + fm->pathbar_cursor = fm->pathbar_len; + } else if (key.ascii >= 32 && key.ascii < 127 && fm->pathbar_len < 254) { + for (int i = fm->pathbar_len; i > fm->pathbar_cursor; i--) + fm->pathbar_buf[i] = fm->pathbar_buf[i - 1]; + fm->pathbar_buf[fm->pathbar_cursor] = key.ascii; + fm->pathbar_cursor++; + fm->pathbar_len++; + fm->pathbar_buf[fm->pathbar_len] = '\0'; + } + return; + } + + // ---- Rename mode key handling ---- + if (fm->rename_active) { + if (key.ascii == '\n' || key.ascii == '\r') { + filemanager_finish_rename(fm); + } else if (key.scancode == 0x01) { + // Escape + filemanager_cancel_rename(fm); + } else if (key.ascii == '\b' || key.scancode == 0x0E) { + // Backspace + if (fm->rename_cursor > 0) { + for (int i = fm->rename_cursor - 1; i < fm->rename_len - 1; i++) + fm->rename_buf[i] = fm->rename_buf[i + 1]; + fm->rename_len--; + fm->rename_cursor--; + fm->rename_buf[fm->rename_len] = '\0'; + } + } else if (key.scancode == 0x53) { + // Delete key + if (fm->rename_cursor < fm->rename_len) { + for (int i = fm->rename_cursor; i < fm->rename_len - 1; i++) + fm->rename_buf[i] = fm->rename_buf[i + 1]; + fm->rename_len--; + fm->rename_buf[fm->rename_len] = '\0'; + } + } else if (key.scancode == 0x4B) { + // Left arrow + if (fm->rename_cursor > 0) fm->rename_cursor--; + } else if (key.scancode == 0x4D) { + // Right arrow + if (fm->rename_cursor < fm->rename_len) fm->rename_cursor++; + } else if (key.scancode == 0x47) { + // Home + fm->rename_cursor = 0; + } else if (key.scancode == 0x4F) { + // End + fm->rename_cursor = fm->rename_len; + } else if (key.ascii >= 32 && key.ascii < 127) { + // Printable character (reject / and other FS-unsafe chars) + if (key.ascii != '/' && key.ascii != '\\' && fm->rename_len < 62) { + for (int i = fm->rename_len; i > fm->rename_cursor; i--) + fm->rename_buf[i] = fm->rename_buf[i - 1]; + fm->rename_buf[fm->rename_cursor] = key.ascii; + fm->rename_cursor++; + fm->rename_len++; + fm->rename_buf[fm->rename_len] = '\0'; + } + } + return; + } + + // ---- Context menu: Escape to close ---- + if (fm->ctx_open && key.scancode == 0x01) { + filemanager_close_ctx_menu(fm); + return; + } + + // ---- Keyboard shortcuts ---- + if (key.ctrl) { + if (key.ascii == 'c' || key.ascii == 'C') { + filemanager_do_copy(fm); + return; + } + if (key.ascii == 'x' || key.ascii == 'X') { + filemanager_do_cut(fm); + return; + } + if (key.ascii == 'v' || key.ascii == 'V') { + filemanager_do_paste(fm); + return; + } + } + + // F2 = rename + if (key.scancode == 0x3C) { + filemanager_start_rename(fm); + return; + } + if (key.ascii == '\b' || key.scancode == 0x0E) { filemanager_go_up(fm); } else if (key.scancode == 0x48) { // Up arrow if (fm->grid_view) { - Rect cr = win->content_rect(); - int cols = (cr.w - FM_SCROLLBAR_W) / FM_GRID_CELL_W; + Rect cr_r = win->content_rect(); + int cols = (cr_r.w - FM_SCROLLBAR_W) / FM_GRID_CELL_W; if (cols < 1) cols = 1; if (fm->selected >= cols) fm->selected -= cols; } else { @@ -890,8 +1851,8 @@ static void filemanager_on_key(Window* win, const Montauk::KeyEvent& key) { } else if (key.scancode == 0x50) { // Down arrow if (fm->grid_view) { - Rect cr = win->content_rect(); - int cols = (cr.w - FM_SCROLLBAR_W) / FM_GRID_CELL_W; + Rect cr_r = win->content_rect(); + int cols = (cr_r.w - FM_SCROLLBAR_W) / FM_GRID_CELL_W; if (cols < 1) cols = 1; if (fm->selected + cols < fm->entry_count) fm->selected += cols; } else { @@ -904,38 +1865,11 @@ static void filemanager_on_key(Window* win, const Montauk::KeyEvent& key) { // Right arrow (grid view only) if (fm->selected < fm->entry_count - 1) fm->selected++; } else if (key.ascii == '\n' || key.ascii == '\r') { - if (fm->selected >= 0 && fm->selected < fm->entry_count) { - if (fm->at_drives_root && fm->entry_types[fm->selected] == 3) { - int d = fm->drive_indices[fm->selected]; - char dpath[8]; - if (d < 10) { - dpath[0] = '0' + d; dpath[1] = ':'; dpath[2] = '/'; dpath[3] = '\0'; - } else { - dpath[0] = '1'; dpath[1] = '0' + (d - 10); dpath[2] = ':'; dpath[3] = '/'; dpath[4] = '\0'; - } - montauk::strcpy(fm->current_path, dpath); - filemanager_push_history(fm); - filemanager_read_dir(fm); - } else if (fm->is_dir[fm->selected]) { - filemanager_navigate(fm, fm->entry_names[fm->selected]); - } - } + if (fm->selected >= 0 && fm->selected < fm->entry_count) + filemanager_open_entry(fm, fm->selected); } else if (key.scancode == 0x53) { // Delete key - if (fm->selected >= 0 && fm->selected < fm->entry_count - && !fm->at_drives_root && fm->entry_types[fm->selected] != 3) { - char fullpath[512]; - montauk::strcpy(fullpath, fm->current_path); - int plen = montauk::slen(fullpath); - if (plen > 0 && fullpath[plen - 1] != '/') - str_append(fullpath, "/", 512); - str_append(fullpath, fm->entry_names[fm->selected], 512); - if (fm->is_dir[fm->selected]) - filemanager_delete_recursive(fullpath); - else - montauk::fdelete(fullpath); - filemanager_read_dir(fm); - } + filemanager_delete_selected(fm); } else if (key.alt && key.scancode == 0x4B) { // Alt+Left: go back filemanager_go_back(fm); @@ -947,6 +1881,8 @@ static void filemanager_on_key(Window* win, const Montauk::KeyEvent& key) { static void filemanager_on_close(Window* win) { if (win->app_data) { + FileManagerState* fm = (FileManagerState*)win->app_data; + filemanager_free_app_icons(fm); montauk::mfree(win->app_data); win->app_data = nullptr; } @@ -975,9 +1911,26 @@ void open_filemanager(DesktopState* ds) { // Lazy-load file manager icons on first open if (ds && !ds->icon_drive.pixels) { Color defColor = colors::ICON_COLOR; - ds->icon_drive = svg_load("0:/icons/drive-harddisk.svg", 16, 16, defColor); - ds->icon_drive_lg = svg_load("0:/icons/drive-harddisk.svg", 48, 48, defColor); - ds->icon_delete = svg_load("0:/icons/trash-empty.svg", 16, 16, defColor); + ds->icon_drive = svg_load("0:/icons/drive-harddisk.svg", 16, 16, defColor); + ds->icon_drive_lg = svg_load("0:/icons/drive-harddisk.svg", 48, 48, defColor); + ds->icon_home_folder = svg_load("0:/icons/folder-blue-home.svg", 16, 16, defColor); + ds->icon_home_folder_lg = svg_load("0:/icons/folder-blue-home.svg", 48, 48, defColor); + ds->icon_apps = svg_load("0:/icons/folder-blue-development.svg", 16, 16, defColor); + ds->icon_apps_lg = svg_load("0:/icons/folder-blue-development.svg", 48, 48, defColor); + + // Special user folder icons + for (int sf = 0; sf < SF_COUNT; sf++) { + char icon_path[128]; + snprintf(icon_path, 128, "0:/icons/%s", sf_icons[sf]); + ds->icon_special_folder[sf] = svg_load(icon_path, 16, 16, defColor); + ds->icon_special_folder_lg[sf] = svg_load(icon_path, 48, 48, defColor); + } + ds->icon_delete = svg_load("0:/icons/trash-empty.svg", 16, 16, defColor); + ds->icon_copy = svg_load("0:/icons/edit-copy.svg", 16, 16, defColor); + ds->icon_cut = svg_load("0:/icons/edit-cut.svg", 16, 16, defColor); + ds->icon_paste = svg_load("0:/icons/edit-paste.svg", 16, 16, defColor); + ds->icon_rename = svg_load("0:/icons/edit-rename.svg", 16, 16, defColor); + ds->icon_folder_new = svg_load("0:/icons/folder-new.svg", 16, 16, defColor); } filemanager_read_drives(fm); diff --git a/programs/src/desktop/apps/app_texteditor.cpp b/programs/src/desktop/apps/app_texteditor.cpp index 58f8c8b..f83627e 100644 --- a/programs/src/desktop/apps/app_texteditor.cpp +++ b/programs/src/desktop/apps/app_texteditor.cpp @@ -11,14 +11,15 @@ // Text Editor state // ============================================================================ -static constexpr int TE_TOOLBAR_H = 36; -static constexpr int TE_PATHBAR_H = 32; -static constexpr int TE_STATUS_H = 24; -static constexpr int TE_LINE_NUM_W = 48; -static constexpr int TE_INIT_CAP = 4096; -static constexpr int TE_MAX_CAP = 262144; // 256KB -static constexpr int TE_MAX_LINES = 16384; -static constexpr int TE_TAB_WIDTH = 4; +static constexpr int TE_TOOLBAR_H = 36; +static constexpr int TE_PATHBAR_H = 32; +static constexpr int TE_STATUS_H = 24; +static constexpr int TE_LINE_NUM_W = 48; +static constexpr int TE_SCROLLBAR_W = 12; +static constexpr int TE_INIT_CAP = 4096; +static constexpr int TE_MAX_CAP = 262144; // 256KB +static constexpr int TE_MAX_LINES = 16384; +static constexpr int TE_TAB_WIDTH = 4; struct TextEditorState { char* buffer; @@ -32,10 +33,20 @@ struct TextEditorState { int scroll_y; // first visible line int scroll_x; // horizontal scroll in pixels bool modified; + bool cursor_moved; // set when cursor moves, triggers scroll-to-cursor char filepath[256]; char filename[64]; DesktopState* desktop; + // Selection + int sel_anchor; // byte position where selection started + int sel_end; // byte position where selection extends to + bool has_selection; + bool mouse_selecting; + + // Scrollbar + Scrollbar scrollbar; + bool show_pathbar; char pathbar_text[256]; int pathbar_cursor; @@ -71,6 +82,7 @@ static void te_update_cursor_pos(TextEditorState* te) { } } te->cursor_col = te->cursor_pos - te->line_offsets[te->cursor_line]; + te->cursor_moved = true; } static int te_line_length(TextEditorState* te, int line) { @@ -206,11 +218,65 @@ static void te_move_end(TextEditorState* te) { te_update_cursor_pos(te); } +// ============================================================================ +// Selection +// ============================================================================ + +static void te_clear_selection(TextEditorState* te) { + te->has_selection = false; + te->sel_anchor = 0; + te->sel_end = 0; +} + +static void te_sel_range(TextEditorState* te, int* out_start, int* out_end) { + if (te->sel_anchor < te->sel_end) { + *out_start = te->sel_anchor; + *out_end = te->sel_end; + } else { + *out_start = te->sel_end; + *out_end = te->sel_anchor; + } +} + +static void te_start_selection(TextEditorState* te) { + if (!te->has_selection) { + te->sel_anchor = te->cursor_pos; + te->sel_end = te->cursor_pos; + te->has_selection = true; + } +} + +static void te_update_selection(TextEditorState* te) { + te->sel_end = te->cursor_pos; + if (te->sel_anchor == te->sel_end) + te->has_selection = false; +} + +static void te_delete_selection(TextEditorState* te) { + if (!te->has_selection) return; + + int sel_s, sel_e; + te_sel_range(te, &sel_s, &sel_e); + int count = sel_e - sel_s; + if (count <= 0) { te_clear_selection(te); return; } + + // Remove bytes [sel_s, sel_e) from buffer + for (int i = sel_s; i < te->buf_len - count; i++) + te->buffer[i] = te->buffer[i + count]; + te->buf_len -= count; + + te->cursor_pos = sel_s; + te->modified = true; + te_clear_selection(te); + te_recompute_lines(te); + te_update_cursor_pos(te); +} + // ============================================================================ // Scrolling // ============================================================================ -static void te_ensure_cursor_visible(TextEditorState* te, int visible_lines, int content_w) { +static void te_ensure_cursor_visible(TextEditorState* te, int visible_lines, int text_area_w) { if (te->cursor_line < te->scroll_y) { te->scroll_y = te->cursor_line; } @@ -218,10 +284,16 @@ static void te_ensure_cursor_visible(TextEditorState* te, int visible_lines, int te->scroll_y = te->cursor_line - visible_lines + 1; } + // Clamp scroll_y + int max_scroll_y = te->line_count - visible_lines; + if (max_scroll_y < 0) max_scroll_y = 0; + if (te->scroll_y > max_scroll_y) te->scroll_y = max_scroll_y; + if (te->scroll_y < 0) te->scroll_y = 0; + // Horizontal scroll int cell_w = mono_cell_width(); int cursor_px = te->cursor_col * cell_w; - int view_w = content_w - TE_LINE_NUM_W; + int view_w = text_area_w - TE_LINE_NUM_W - TE_SCROLLBAR_W; if (cursor_px - te->scroll_x > view_w - cell_w * 2) { te->scroll_x = cursor_px - view_w + cell_w * 4; } @@ -375,8 +447,24 @@ static void texteditor_on_draw(Window* win, Framebuffer& fb) { int text_area_h = c.h - editor_y_start - TE_STATUS_H; int visible_lines = text_area_h / cell_h; if (visible_lines < 1) visible_lines = 1; + int text_area_w = c.w - TE_SCROLLBAR_W; - te_ensure_cursor_visible(te, visible_lines, c.w); + // Only scroll-to-cursor when the cursor actually moved + if (te->cursor_moved) { + te_ensure_cursor_visible(te, visible_lines, c.w); + te->cursor_moved = false; + } + + // Update scrollbar + te->scrollbar.bounds = {c.w - TE_SCROLLBAR_W, editor_y_start, TE_SCROLLBAR_W, text_area_h}; + te->scrollbar.content_height = te->line_count * cell_h; + te->scrollbar.view_height = text_area_h; + te->scrollbar.scroll_offset = te->scroll_y * cell_h; + { + int ms = te->scrollbar.max_scroll(); + if (te->scrollbar.scroll_offset > ms) te->scrollbar.scroll_offset = ms; + if (te->scrollbar.scroll_offset < 0) te->scrollbar.scroll_offset = 0; + } // Line number gutter background c.fill_rect(0, editor_y_start, TE_LINE_NUM_W, text_area_h, Color::from_rgb(0xF0, 0xF0, 0xF0)); @@ -384,6 +472,11 @@ static void texteditor_on_draw(Window* win, Framebuffer& fb) { // Gutter separator c.vline(TE_LINE_NUM_W, editor_y_start, text_area_h, colors::BORDER); + // Selection range + int sel_s = 0, sel_e = 0; + if (te->has_selection) te_sel_range(te, &sel_s, &sel_e); + Color sel_bg = Color::from_rgb(0xB0, 0xD0, 0xF0); + // Draw lines Color linenum_color = Color::from_rgb(0x99, 0x99, 0x99); Color cursor_line_color = Color::from_rgb(0xFF, 0xFD, 0xE8); @@ -398,11 +491,11 @@ static void texteditor_on_draw(Window* win, Framebuffer& fb) { int py = editor_y_start + vis * cell_h; if (py >= editor_y_start + text_area_h) break; - // Cursor line highlighting - if (line == te->cursor_line) { + // Cursor line highlighting (only when no selection) + if (line == te->cursor_line && !te->has_selection) { int hl_h = gui_min(cell_h, editor_y_start + text_area_h - py); if (hl_h > 0) - c.fill_rect(TE_LINE_NUM_W + 1, py, c.w - TE_LINE_NUM_W - 1, hl_h, cursor_line_color); + c.fill_rect(TE_LINE_NUM_W + 1, py, text_area_w - TE_LINE_NUM_W - 1, hl_h, cursor_line_color); } // Line number @@ -417,9 +510,18 @@ static void texteditor_on_draw(Window* win, Framebuffer& fb) { for (int ci = 0; ci < line_len; ci++) { int px = text_start_x + ci * cell_w - te->scroll_x; if (px + cell_w <= TE_LINE_NUM_W + 1) continue; - if (px >= c.w) break; + if (px >= text_area_w) break; + + int byte_pos = line_start + ci; + char ch = te->buffer[byte_pos]; + + // Draw selection highlight behind text + if (te->has_selection && byte_pos >= sel_s && byte_pos < sel_e) { + int hl_h = gui_min(cell_h, editor_y_start + text_area_h - py); + if (hl_h > 0) + c.fill_rect(px, py, cell_w, hl_h, sel_bg); + } - char ch = te->buffer[line_start + ci]; if (ch >= 32 || ch < 0) { if (fonts::mono && fonts::mono->valid) { GlyphCache* gc = fonts::mono->get_cache(fonts::TERM_SIZE); @@ -436,7 +538,7 @@ static void texteditor_on_draw(Window* win, Framebuffer& fb) { if (bits & (0x80 >> fx)) { int dx = px + fx; int dy = py + fy; - if (dx > TE_LINE_NUM_W && dx < c.w && dy >= 0 && dy < c.h) + if (dx > TE_LINE_NUM_W && dx < text_area_w && dy >= 0 && dy < c.h) c.pixels[dy * c.w + dx] = text_px; } } @@ -445,10 +547,23 @@ static void texteditor_on_draw(Window* win, Framebuffer& fb) { } } + // Draw selection highlight for newline at end of line (visual feedback) + if (te->has_selection && line + 1 < te->line_count) { + int nl_pos = line_start + line_len; // the newline byte + if (nl_pos >= sel_s && nl_pos < sel_e) { + int px = text_start_x + line_len * cell_w - te->scroll_x; + if (px > TE_LINE_NUM_W && px < text_area_w) { + int hl_h = gui_min(cell_h, editor_y_start + text_area_h - py); + if (hl_h > 0) + c.fill_rect(px, py, cell_w / 2, hl_h, sel_bg); + } + } + } + // Draw cursor if (line == te->cursor_line) { int cx = text_start_x + te->cursor_col * cell_w - te->scroll_x; - if (cx > TE_LINE_NUM_W && cx + 2 <= c.w) { + if (cx > TE_LINE_NUM_W && cx + 2 <= text_area_w) { int cur_h = gui_min(cell_h, editor_y_start + text_area_h - py); if (cur_h > 0) c.fill_rect(cx, py, 2, cur_h, colors::ACCENT); @@ -456,13 +571,33 @@ static void texteditor_on_draw(Window* win, Framebuffer& fb) { } } + // ---- Scrollbar ---- + if (te->scrollbar.content_height > te->scrollbar.view_height) { + Color sb_fg = (te->scrollbar.hovered || te->scrollbar.dragging) + ? te->scrollbar.hover_fg : te->scrollbar.fg; + int sbx = te->scrollbar.bounds.x; + int sby = te->scrollbar.bounds.y; + int sbw = te->scrollbar.bounds.w; + int sbh = te->scrollbar.bounds.h; + c.fill_rect(sbx, sby, sbw, sbh, colors::SCROLLBAR_BG); + int th = te->scrollbar.thumb_height(); + int tty = te->scrollbar.thumb_y(); + c.fill_rect(sbx + 1, tty, sbw - 2, th, sb_fg); + } + // ---- Status bar ---- int status_y = c.h - TE_STATUS_H; c.fill_rect(0, status_y, c.w, TE_STATUS_H, Color::from_rgb(0x2B, 0x3E, 0x50)); // Cursor position (right side) - char status_right[32]; - snprintf(status_right, 32, "Ln %d, Col %d ", te->cursor_line + 1, te->cursor_col + 1); + char status_right[48]; + if (te->has_selection) { + int ss, se; + te_sel_range(te, &ss, &se); + snprintf(status_right, 48, "%d selected Ln %d, Col %d ", se - ss, te->cursor_line + 1, te->cursor_col + 1); + } else { + snprintf(status_right, 48, "Ln %d, Col %d ", te->cursor_line + 1, te->cursor_col + 1); + } int sr_w = text_width(status_right); int status_text_y = status_y + (TE_STATUS_H - sfh) / 2; c.text(c.w - sr_w - 4, status_text_y, status_right, colors::PANEL_TEXT); @@ -481,6 +616,22 @@ static void texteditor_on_draw(Window* win, Framebuffer& fb) { // Mouse handling // ============================================================================ +static int te_hit_test(TextEditorState* te, int local_x, int local_y, int editor_y_start) { + int cell_w = mono_cell_width(); + int cell_h = mono_cell_height(); + + int clicked_line = te->scroll_y + (local_y - editor_y_start) / cell_h; + if (clicked_line >= te->line_count) clicked_line = te->line_count - 1; + if (clicked_line < 0) clicked_line = 0; + + int clicked_col = (local_x - TE_LINE_NUM_W - 4 + te->scroll_x + cell_w / 2) / cell_w; + if (clicked_col < 0) clicked_col = 0; + int line_len = te_line_length(te, clicked_line); + if (clicked_col > line_len) clicked_col = line_len; + + return te->line_offsets[clicked_line] + clicked_col; +} + static void texteditor_on_mouse(Window* win, MouseEvent& ev) { TextEditorState* te = (TextEditorState*)win->app_data; if (!te) return; @@ -489,19 +640,32 @@ static void texteditor_on_mouse(Window* win, MouseEvent& ev) { int local_x = ev.x - cr.x; int local_y = ev.y - cr.y; - int cell_w = mono_cell_width(); int cell_h = mono_cell_height(); int editor_y_start = TE_TOOLBAR_H + (te->show_pathbar ? TE_PATHBAR_H : 0); int text_area_h = cr.h - editor_y_start - TE_STATUS_H; + // ---- Scrollbar ---- + { + MouseEvent local_ev = ev; + local_ev.x = local_x; + local_ev.y = local_y; + bool was_dragging = te->scrollbar.dragging; + te->scrollbar.handle_mouse(local_ev); + if (te->scrollbar.dragging || was_dragging) { + // Convert pixel scroll offset back to line index + if (cell_h > 0) + te->scroll_y = te->scrollbar.scroll_offset / cell_h; + return; + } + } + // ---- Toolbar clicks ---- if (ev.left_pressed() && local_y < TE_TOOLBAR_H) { // Open button if (local_x >= 4 && local_x < 28 && local_y >= 6 && local_y < 30) { te->show_pathbar = !te->show_pathbar; if (te->show_pathbar) { - // Pre-fill with current filepath montauk::strncpy(te->pathbar_text, te->filepath, 255); te->pathbar_len = montauk::slen(te->pathbar_text); te->pathbar_cursor = te->pathbar_len; @@ -519,14 +683,12 @@ static void texteditor_on_mouse(Window* win, MouseEvent& ev) { // ---- Path bar clicks ---- if (te->show_pathbar && local_y >= TE_TOOLBAR_H && local_y < TE_TOOLBAR_H + TE_PATHBAR_H) { if (ev.left_pressed()) { - // Check "Open" button region int btn_w = 56; int inp_w = cr.w - 8 - btn_w - 12; int ob_x = 8 + inp_w + 6; if (local_x >= ob_x && local_x < ob_x + btn_w) { if (te->pathbar_text[0]) { te_load_file(te, te->pathbar_text); - // Update window title char title[64]; snprintf(title, 64, "%s - Editor", te->filename); montauk::strncpy(win->title, title, 63); @@ -537,26 +699,42 @@ static void texteditor_on_mouse(Window* win, MouseEvent& ev) { return; } - // ---- Editor area clicks ---- - if (ev.left_pressed() && local_y >= editor_y_start && local_y < editor_y_start + text_area_h && local_x > TE_LINE_NUM_W) { - int clicked_line = te->scroll_y + (local_y - editor_y_start) / cell_h; - if (clicked_line >= te->line_count) clicked_line = te->line_count - 1; - if (clicked_line < 0) clicked_line = 0; - - int clicked_col = (local_x - TE_LINE_NUM_W - 4 + te->scroll_x + cell_w / 2) / cell_w; - if (clicked_col < 0) clicked_col = 0; - int line_len = te_line_length(te, clicked_line); - if (clicked_col > line_len) clicked_col = line_len; - - te->cursor_pos = te->line_offsets[clicked_line] + clicked_col; + // ---- Editor area: mouse press - start selection or place cursor ---- + if (ev.left_pressed() && local_y >= editor_y_start && local_y < editor_y_start + text_area_h + && local_x > TE_LINE_NUM_W && local_x < cr.w - TE_SCROLLBAR_W) { + int pos = te_hit_test(te, local_x, local_y, editor_y_start); + te->cursor_pos = pos; te_update_cursor_pos(te); + + te->sel_anchor = pos; + te->sel_end = pos; + te->has_selection = false; + te->mouse_selecting = true; + return; + } + + // ---- Editor area: mouse drag - extend selection ---- + if (te->mouse_selecting && ev.left_held() && local_y >= editor_y_start - 20) { + int pos = te_hit_test(te, local_x, local_y, editor_y_start); + te->sel_end = pos; + te->cursor_pos = pos; + te_update_cursor_pos(te); + te->has_selection = (te->sel_anchor != te->sel_end); + return; + } + + // ---- Mouse release: end selection ---- + if (te->mouse_selecting && ev.left_released()) { + te->mouse_selecting = false; + return; } // ---- Scroll ---- if (ev.scroll != 0 && local_y >= editor_y_start && local_y < editor_y_start + text_area_h) { te->scroll_y -= ev.scroll * 3; if (te->scroll_y < 0) te->scroll_y = 0; - int max_scroll = te->line_count - (text_area_h / cell_h) + 1; + int visible_lines = text_area_h / cell_h; + int max_scroll = te->line_count - visible_lines; if (max_scroll < 0) max_scroll = 0; if (te->scroll_y > max_scroll) te->scroll_y = max_scroll; } @@ -635,33 +813,126 @@ static void texteditor_on_key(Window* win, const Montauk::KeyEvent& key) { return; } - // Arrow keys - if (key.scancode == 0x48) { te_move_up(te); return; } - if (key.scancode == 0x50) { te_move_down(te); return; } - if (key.scancode == 0x4B) { te_move_left(te); return; } - if (key.scancode == 0x4D) { te_move_right(te); return; } + // Ctrl+A: select all + if (key.ctrl && (key.ascii == 'a' || key.ascii == 'A')) { + te->sel_anchor = 0; + te->sel_end = te->buf_len; + te->has_selection = (te->buf_len > 0); + te->cursor_pos = te->buf_len; + te_update_cursor_pos(te); + return; + } + + // Arrow keys (Shift extends selection) + if (key.scancode == 0x48) { // Up + if (key.shift) te_start_selection(te); + else if (te->has_selection) te_clear_selection(te); + te_move_up(te); + if (key.shift) te_update_selection(te); + return; + } + if (key.scancode == 0x50) { // Down + if (key.shift) te_start_selection(te); + else if (te->has_selection) te_clear_selection(te); + te_move_down(te); + if (key.shift) te_update_selection(te); + return; + } + if (key.scancode == 0x4B) { // Left + if (key.shift) { + te_start_selection(te); + te_move_left(te); + te_update_selection(te); + } else if (te->has_selection) { + int s, e; te_sel_range(te, &s, &e); + te->cursor_pos = s; + te_update_cursor_pos(te); + te_clear_selection(te); + } else { + te_move_left(te); + } + return; + } + if (key.scancode == 0x4D) { // Right + if (key.shift) { + te_start_selection(te); + te_move_right(te); + te_update_selection(te); + } else if (te->has_selection) { + int s, e; te_sel_range(te, &s, &e); + te->cursor_pos = e; + te_update_cursor_pos(te); + te_clear_selection(te); + } else { + te_move_right(te); + } + return; + } // Home - if (key.scancode == 0x47) { te_move_home(te); return; } + if (key.scancode == 0x47) { + if (key.shift) te_start_selection(te); + else if (te->has_selection) te_clear_selection(te); + te_move_home(te); + if (key.shift) te_update_selection(te); + return; + } // End - if (key.scancode == 0x4F) { te_move_end(te); return; } + if (key.scancode == 0x4F) { + if (key.shift) te_start_selection(te); + else if (te->has_selection) te_clear_selection(te); + te_move_end(te); + if (key.shift) te_update_selection(te); + return; + } + + // Page Up + if (key.scancode == 0x49) { + if (key.shift) te_start_selection(te); + else if (te->has_selection) te_clear_selection(te); + int cell_h = mono_cell_height(); + int visible = (te->scrollbar.view_height > 0 && cell_h > 0) + ? te->scrollbar.view_height / cell_h : 20; + for (int i = 0; i < visible; i++) te_move_up(te); + if (key.shift) te_update_selection(te); + return; + } + // Page Down + if (key.scancode == 0x51) { + if (key.shift) te_start_selection(te); + else if (te->has_selection) te_clear_selection(te); + int cell_h = mono_cell_height(); + int visible = (te->scrollbar.view_height > 0 && cell_h > 0) + ? te->scrollbar.view_height / cell_h : 20; + for (int i = 0; i < visible; i++) te_move_down(te); + if (key.shift) te_update_selection(te); + return; + } + // Delete - if (key.scancode == 0x53) { te_delete_char(te); return; } + if (key.scancode == 0x53) { + if (te->has_selection) te_delete_selection(te); + else te_delete_char(te); + return; + } // Backspace if (key.ascii == '\b' || key.scancode == 0x0E) { - te_backspace(te); + if (te->has_selection) te_delete_selection(te); + else te_backspace(te); return; } // Enter if (key.ascii == '\n' || key.ascii == '\r') { + if (te->has_selection) te_delete_selection(te); te_insert_char(te, '\n'); return; } // Tab if (key.ascii == '\t') { + if (te->has_selection) te_delete_selection(te); for (int i = 0; i < TE_TAB_WIDTH; i++) { te_insert_char(te, ' '); } @@ -670,6 +941,7 @@ static void texteditor_on_key(Window* win, const Montauk::KeyEvent& key) { // Printable characters if (key.ascii >= 32 && key.ascii < 127) { + if (te->has_selection) te_delete_selection(te); te_insert_char(te, key.ascii); return; } @@ -706,6 +978,12 @@ void open_texteditor(DesktopState* ds) { te->pathbar_text[0] = '\0'; te->pathbar_cursor = 0; te->pathbar_len = 0; + te->has_selection = false; + te->mouse_selecting = false; + te->sel_anchor = 0; + te->sel_end = 0; + te->cursor_moved = true; + te->scrollbar.init(0, 0, TE_SCROLLBAR_W, 100); te_recompute_lines(te); te_update_cursor_pos(te); @@ -718,7 +996,6 @@ void open_texteditor(DesktopState* ds) { } void open_texteditor_with_file(DesktopState* ds, const char* path) { - // Extract filename for window title const char* name = path; for (int i = 0; path[i]; i++) { if (path[i] == '/') name = path + i + 1; @@ -743,9 +1020,12 @@ void open_texteditor_with_file(DesktopState* ds, const char* path) { te->pathbar_text[0] = '\0'; te->pathbar_cursor = 0; te->pathbar_len = 0; + te->has_selection = false; + te->mouse_selecting = false; + te->sel_anchor = 0; + te->sel_end = 0; + te->scrollbar.init(0, 0, TE_SCROLLBAR_W, 100); - // Initialize line index for empty document first (ensures line_offsets - // is non-null even if te_load_file fails to open the file) te_recompute_lines(te); te_update_cursor_pos(te); diff --git a/programs/src/installer/actions.cpp b/programs/src/installer/actions.cpp index 04feaf0..51e2191 100644 --- a/programs/src/installer/actions.cpp +++ b/programs/src/installer/actions.cpp @@ -736,6 +736,18 @@ void do_update() { flush_ui(); st.step = STEP_ERROR; return; } + // Step 4: Update lib/ — compiler runtime, headers, libc + add_log("Updating lib/..."); + flush_ui(); + + snprintf(path_buf, sizeof(path_buf), "%d:/lib", drive_num); + montauk::fmkdir(path_buf); + + if (!copy_recursive("0:/lib", path_buf)) { + add_log("ERROR: Failed to update lib/"); + flush_ui(); st.step = STEP_ERROR; return; + } + char copy_msg[64]; snprintf(copy_msg, sizeof(copy_msg), " %d files, %d directories updated", g_files_copied, g_dirs_created); diff --git a/programs/src/mtkfetch/main.cpp b/programs/src/mtkfetch/main.cpp new file mode 100644 index 0000000..8baac43 --- /dev/null +++ b/programs/src/mtkfetch/main.cpp @@ -0,0 +1,279 @@ +/* + * main.cpp + * mtkfetch - System information display + * Copyright (c) 2026 Daniel Hammer +*/ + +#include +#include +#include +#include + +// ==== ANSI color codes ==== + +#define RST "\033[0m" +#define BOLD "\033[1m" +#define BWHT "\033[1;37m" +#define BCYN "\033[1;36m" +#define CYN "\033[36m" +#define DGRY "\033[90m" + +// ==== String helpers ==== + +static char* app(char* d, const char* s) { + while (*s) *d++ = *s++; + *d = '\0'; + return d; +} + +static char* app_int(char* d, uint64_t n) { + if (n == 0) { *d++ = '0'; *d = '\0'; return d; } + char tmp[20]; + int i = 0; + while (n > 0) { tmp[i++] = '0' + (n % 10); n /= 10; } + for (int j = i - 1; j >= 0; j--) *d++ = tmp[j]; + *d = '\0'; + return d; +} + +static void pad(int n) { + for (int i = 0; i < n; i++) montauk::putchar(' '); +} + +// ==== MT block letter ASCII art ==== +// +// Each line has a known visible width (excluding ANSI codes). +// The print loop pads each line to a fixed column before printing info. + +static constexpr int NUM_LINES = 19; +static constexpr int INFO_COL = 26; + +static const char* art[] = { + /* 0 */ "", + /* 1 */ "", + /* 2 */ BCYN "## ## ##########" RST, + /* 3 */ BCYN "### ### ##########" RST, + /* 4 */ BCYN "#### #### ##" RST, + /* 5 */ BCYN "## ## ## ## ##" RST, + /* 6 */ BCYN "## ### ## ##" RST, + /* 7 */ BCYN "## # ## ##" RST, + /* 8 */ BCYN "## ## ##" RST, + /* 9 */ BCYN "## ## ##" RST, + /* 10 */ BCYN "## ## ##" RST, + /* 11 */ CYN "~~~~~~~~~~~~~~~~~~~~~~~" RST, + /* 12 */ "", + /* 13 */ "", + /* 14 */ "", + /* 15 */ "", + /* 16 */ "", + /* 17 */ "", + /* 18 */ "", +}; + +static const int art_vw[] = { + 0, 0, 23, 23, 19, 19, 19, 19, 19, 19, + 19, 23, 0, 0, 0, 0, 0, 0, 0, +}; + +extern "C" void _start() { + // ==== Gather system information ==== + + Montauk::SysInfo sysinfo; + montauk::get_info(&sysinfo); + + auto doc = montauk::config::load("session"); + const char* username = doc.get_string("session.username", "user"); + + uint64_t ms = montauk::get_milliseconds(); + uint64_t total_secs = ms / 1000; + uint64_t hours = total_secs / 3600; + uint64_t mins = (total_secs % 3600) / 60; + uint64_t secs = total_secs % 60; + + Montauk::MemStats mem; + montauk::memstats(&mem); + + Montauk::FbInfo fb; + montauk::fb_info(&fb); + + int tcols = 0, trows = 0; + montauk::termsize(&tcols, &trows); + + Montauk::DevInfo devs[32]; + int ndev = montauk::devlist(devs, 32); + const char* cpu_name = "Unknown"; + const char* gpu_name = "Unknown"; + bool found_cpu = false, found_gpu = false; + for (int i = 0; i < ndev; i++) { + if (devs[i].category == 0 && !found_cpu) { + cpu_name = devs[i].name; + found_cpu = true; + } + if (devs[i].category == 6 && !found_gpu) { + gpu_name = devs[i].name; + found_gpu = true; + } + } + + Montauk::ProcInfo procs[64]; + int nproc = montauk::proclist(procs, 64); + int active = 0; + for (int i = 0; i < nproc; i++) { + if (procs[i].state == 1 || procs[i].state == 2) active++; + } + + Montauk::NetCfg net; + montauk::get_netcfg(&net); + + // ==== Build info lines ==== + + char info[NUM_LINES][256]; + for (int i = 0; i < NUM_LINES; i++) info[i][0] = '\0'; + + // Line 1: user@montauk + { + char* p = app(info[1], BCYN BOLD); + p = app(p, username); + p = app(p, "@montauk" RST); + } + + // Line 2: separator + { + char* p = info[2]; + int len = montauk::slen(username) + 8; + for (int i = 0; i < len; i++) *p++ = '-'; + *p = '\0'; + } + + // Line 3: OS + { + char* p = app(info[3], BCYN "OS" RST ": "); + p = app(p, sysinfo.osName); + p = app(p, " v"); + p = app(p, sysinfo.osVersion); + } + + // Line 4: API version + { + char* p = app(info[4], BCYN "API" RST ": "); + p = app_int(p, sysinfo.apiVersion); + } + + // Line 5: Uptime + { + char* p = app(info[5], BCYN "Uptime" RST ": "); + if (hours > 0) { + p = app_int(p, hours); + p = app(p, "h "); + } + p = app_int(p, mins); + p = app(p, "m "); + p = app_int(p, secs); + p = app(p, "s"); + } + + // Line 6: CPU + { + char* p = app(info[6], BCYN "CPU" RST ": "); + p = app(p, cpu_name); + } + + // Line 7: GPU + { + char* p = app(info[7], BCYN "GPU" RST ": "); + p = app(p, gpu_name); + } + + // Line 8: Memory + { + char* p = app(info[8], BCYN "Memory" RST ": "); + p = app_int(p, mem.usedBytes / 1048576); + p = app(p, " MiB / "); + p = app_int(p, mem.totalBytes / 1048576); + p = app(p, " MiB"); + } + + // Line 9: Resolution + { + char* p = app(info[9], BCYN "Resolution" RST ": "); + p = app_int(p, fb.width); + *p++ = 'x'; + p = app_int(p, fb.height); + *p = '\0'; + } + + // Line 10: Terminal + { + char* p = app(info[10], BCYN "Terminal" RST ": "); + p = app_int(p, tcols); + *p++ = 'x'; + p = app_int(p, trows); + *p = '\0'; + } + + // Line 11: Processes + { + char* p = app(info[11], BCYN "Processes" RST ": "); + p = app_int(p, active); + } + + // Line 12: Network + { + char* p = app(info[12], BCYN "Network" RST ": "); + uint32_t ip = net.ipAddress; + if (ip) { + p = app_int(p, ip & 0xFF); + *p++ = '.'; + p = app_int(p, (ip >> 8) & 0xFF); + *p++ = '.'; + p = app_int(p, (ip >> 16) & 0xFF); + *p++ = '.'; + p = app_int(p, (ip >> 24) & 0xFF); + *p = '\0'; + } else { + p = app(p, "Not configured"); + } + } + + // Line 13: Shell + app(info[13], BCYN "Shell" RST ": MontaukOS Shell"); + + // Line 15: Color palette (normal) + { + char* p = info[15]; + for (int c = 0; c < 8; c++) { + p = app(p, "\033[4"); + *p++ = '0' + c; + p = app(p, "m "); + } + p = app(p, RST); + } + + // Line 16: Color palette (bright) + { + char* p = info[16]; + for (int c = 0; c < 8; c++) { + p = app(p, "\033[10"); + *p++ = '0' + c; + p = app(p, "m "); + } + p = app(p, RST); + } + + doc.destroy(); + + // ==== Print output ==== + + montauk::putchar('\n'); + for (int i = 0; i < NUM_LINES; i++) { + montauk::print(art[i]); + int p = INFO_COL - art_vw[i]; + if (p < 1) p = 1; + pad(p); + if (info[i][0]) montauk::print(info[i]); + montauk::putchar('\n'); + } + montauk::putchar('\n'); + + montauk::exit(0); +} diff --git a/programs/src/paint/Makefile b/programs/src/paint/Makefile new file mode 100644 index 0000000..6a778f1 --- /dev/null +++ b/programs/src/paint/Makefile @@ -0,0 +1,86 @@ +# Makefile for paint (standalone Window Server app) on MontaukOS +# Copyright (c) 2026 Daniel Hammer + +MAKEFLAGS += -rR +.SUFFIXES: + +# ---- Toolchain ---- + +TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-elf- +ifneq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) + CXX := $(TOOLCHAIN_PREFIX)g++ +else + CXX := g++ +endif + +# ---- Paths ---- + +PROG_INC := ../../include +LINK_LD := ../../link.ld +BINDIR := ../../bin +OBJDIR := obj +LIBDIR := ../../lib + +# ---- Compiler flags ---- + +CXXFLAGS := \ + -std=gnu++20 \ + -g -O2 -pipe \ + -Wall \ + -Wextra \ + -Wno-unused-parameter \ + -Wno-unused-function \ + -nostdinc \ + -ffreestanding \ + -fno-stack-protector \ + -fno-stack-check \ + -fno-PIC \ + -fno-rtti \ + -fno-exceptions \ + -ffunction-sections \ + -fdata-sections \ + -m64 \ + -march=x86-64 \ + -msse \ + -msse2 \ + -mno-red-zone \ + -mcmodel=small \ + -I $(PROG_INC) \ + -isystem $(PROG_INC)/libc \ + -isystem ../../../kernel/freestnd-c-hdrs/x86_64/include \ + -isystem ../../../kernel/freestnd-cxx-hdrs/x86_64/include + +# ---- Linker flags ---- + +LDFLAGS := \ + -nostdlib \ + -static \ + -Wl,--build-id=none \ + -Wl,--gc-sections \ + -Wl,-m,elf_x86_64 \ + -z max-page-size=0x1000 \ + -T $(LINK_LD) + +# ---- Source files ---- + +SRCS := main.cpp helpers.cpp drawing.cpp render.cpp stb_truetype_impl.cpp +OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o)) + +# ---- Target ---- + +TARGET := $(BINDIR)/apps/paint/paint.elf + +.PHONY: all clean + +all: $(TARGET) + +$(TARGET): $(OBJS) $(LINK_LD) Makefile + mkdir -p $(BINDIR)/apps/paint + $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(LIBDIR)/libc/liblibc.a -o $@ + +$(OBJDIR)/%.o: %.cpp Makefile + mkdir -p $(OBJDIR) + $(CXX) $(CXXFLAGS) -c $< -o $@ + +clean: + rm -rf $(OBJDIR) $(TARGET) diff --git a/programs/src/paint/drawing.cpp b/programs/src/paint/drawing.cpp new file mode 100644 index 0000000..ee98b1b --- /dev/null +++ b/programs/src/paint/drawing.cpp @@ -0,0 +1,238 @@ +/* + * drawing.cpp + * Canvas drawing operations for Paint app + * Copyright (c) 2026 Daniel Hammer + */ + +#include "paint.h" + +// ============================================================================ +// Basic canvas operations +// ============================================================================ + +void canvas_put_pixel(int x, int y, Color c) { + if (x < 0 || x >= g_canvas_w || y < 0 || y >= g_canvas_h) return; + g_canvas[y * g_canvas_w + x] = c.to_pixel(); +} + +void canvas_clear(Color c) { + uint32_t v = c.to_pixel(); + int total = g_canvas_w * g_canvas_h; + for (int i = 0; i < total; i++) + g_canvas[i] = v; +} + +// ============================================================================ +// Brush (filled circle stamp) +// ============================================================================ + +void canvas_draw_brush(int cx, int cy, Color c, int size) { + if (size <= 1) { + canvas_put_pixel(cx, cy, c); + return; + } + int r = size / 2; + int r2 = r * r; + for (int dy = -r; dy <= r; dy++) + for (int dx = -r; dx <= r; dx++) + if (dx * dx + dy * dy <= r2) + canvas_put_pixel(cx + dx, cy + dy, c); +} + +// ============================================================================ +// Bresenham line +// ============================================================================ + +void canvas_draw_line(int x0, int y0, int x1, int y1, Color c, int thickness) { + int dx = x1 - x0; + int dy = y1 - y0; + if (dx < 0) dx = -dx; + if (dy < 0) dy = -dy; + + int sx = x0 < x1 ? 1 : -1; + int sy = y0 < y1 ? 1 : -1; + int err = dx - dy; + + while (true) { + canvas_draw_brush(x0, y0, c, thickness); + if (x0 == x1 && y0 == y1) break; + int e2 = 2 * err; + if (e2 > -dy) { err -= dy; x0 += sx; } + if (e2 < dx) { err += dx; y0 += sy; } + } +} + +// ============================================================================ +// Rectangle +// ============================================================================ + +void canvas_draw_rect(int x0, int y0, int x1, int y1, Color c, int thickness) { + if (x0 > x1) { int t = x0; x0 = x1; x1 = t; } + if (y0 > y1) { int t = y0; y0 = y1; y1 = t; } + + for (int t = 0; t < thickness; t++) { + for (int x = x0 + t; x <= x1 - t; x++) { + canvas_put_pixel(x, y0 + t, c); + canvas_put_pixel(x, y1 - t, c); + } + for (int y = y0 + t; y <= y1 - t; y++) { + canvas_put_pixel(x0 + t, y, c); + canvas_put_pixel(x1 - t, y, c); + } + } +} + +void canvas_fill_rect(int x0, int y0, int x1, int y1, Color c) { + if (x0 > x1) { int t = x0; x0 = x1; x1 = t; } + if (y0 > y1) { int t = y0; y0 = y1; y1 = t; } + + for (int y = y0; y <= y1; y++) + for (int x = x0; x <= x1; x++) + canvas_put_pixel(x, y, c); +} + +// ============================================================================ +// Ellipse (midpoint algorithm) +// ============================================================================ + +static void ellipse_plot4(int cx, int cy, int x, int y, Color c, int thickness) { + if (thickness <= 1) { + canvas_put_pixel(cx + x, cy + y, c); + canvas_put_pixel(cx - x, cy + y, c); + canvas_put_pixel(cx + x, cy - y, c); + canvas_put_pixel(cx - x, cy - y, c); + } else { + canvas_draw_brush(cx + x, cy + y, c, thickness); + canvas_draw_brush(cx - x, cy + y, c, thickness); + canvas_draw_brush(cx + x, cy - y, c, thickness); + canvas_draw_brush(cx - x, cy - y, c, thickness); + } +} + +void canvas_draw_ellipse(int x0, int y0, int x1, int y1, Color c, int thickness) { + if (x0 > x1) { int t = x0; x0 = x1; x1 = t; } + if (y0 > y1) { int t = y0; y0 = y1; y1 = t; } + + int cx = (x0 + x1) / 2; + int cy = (y0 + y1) / 2; + int a = (x1 - x0) / 2; + int b = (y1 - y0) / 2; + if (a == 0 || b == 0) { + canvas_draw_line(x0, y0, x1, y1, c, thickness); + return; + } + + long long a2 = (long long)a * a; + long long b2 = (long long)b * b; + int x = 0, y = b; + long long d1 = b2 - a2 * b + a2 / 4; + + while (a2 * y > b2 * x) { + ellipse_plot4(cx, cy, x, y, c, thickness); + if (d1 < 0) { + d1 += b2 * (2 * x + 3); + } else { + d1 += b2 * (2 * x + 3) + a2 * (-2 * y + 2); + y--; + } + x++; + } + + long long d2 = b2 * ((long long)(x * 2 + 1) * (x * 2 + 1)) / 4 + + a2 * ((long long)(y - 1) * (y - 1)) + - a2 * b2; + while (y >= 0) { + ellipse_plot4(cx, cy, x, y, c, thickness); + if (d2 > 0) { + d2 += a2 * (-2 * y + 3); + } else { + d2 += b2 * (2 * x + 2) + a2 * (-2 * y + 3); + x++; + } + y--; + } +} + +void canvas_fill_ellipse(int x0, int y0, int x1, int y1, Color c) { + if (x0 > x1) { int t = x0; x0 = x1; x1 = t; } + if (y0 > y1) { int t = y0; y0 = y1; y1 = t; } + + int cx = (x0 + x1) / 2; + int cy = (y0 + y1) / 2; + int a = (x1 - x0) / 2; + int b = (y1 - y0) / 2; + if (a == 0 || b == 0) return; + + for (int dy = -b; dy <= b; dy++) { + // x^2/a^2 + y^2/b^2 <= 1 => x <= a * sqrt(1 - y^2/b^2) + long long x_extent = (long long)a * a * ((long long)b * b - (long long)dy * dy); + if (x_extent < 0) continue; + // Integer sqrt approximation + long long denom = (long long)b * b; + int w = 0; + while ((long long)(w + 1) * (w + 1) * denom <= x_extent) w++; + for (int dx = -w; dx <= w; dx++) + canvas_put_pixel(cx + dx, cy + dy, c); + } +} + +// ============================================================================ +// Flood fill (iterative scanline) +// ============================================================================ + +void canvas_flood_fill(int sx, int sy, Color fill_color) { + if (sx < 0 || sx >= g_canvas_w || sy < 0 || sy >= g_canvas_h) return; + + uint32_t target = g_canvas[sy * g_canvas_w + sx]; + uint32_t fill_px = fill_color.to_pixel(); + if (target == fill_px) return; + + // Simple stack-based flood fill with a bounded stack + static constexpr int STACK_MAX = 65536; + struct Pt { int16_t x, y; }; + Pt* stack = (Pt*)montauk::malloc(STACK_MAX * sizeof(Pt)); + if (!stack) return; + + int sp = 0; + stack[sp++] = {(int16_t)sx, (int16_t)sy}; + g_canvas[sy * g_canvas_w + sx] = fill_px; + + while (sp > 0) { + Pt p = stack[--sp]; + int x = p.x, y = p.y; + + // Scan left + int left = x; + while (left > 0 && g_canvas[y * g_canvas_w + left - 1] == target) { + left--; + g_canvas[y * g_canvas_w + left] = fill_px; + } + + // Scan right + int right = x; + while (right < g_canvas_w - 1 && g_canvas[y * g_canvas_w + right + 1] == target) { + right++; + g_canvas[y * g_canvas_w + right] = fill_px; + } + + // Check above and below + for (int dir = -1; dir <= 1; dir += 2) { + int ny = y + dir; + if (ny < 0 || ny >= g_canvas_h) continue; + bool in_span = false; + for (int px = left; px <= right; px++) { + if (g_canvas[ny * g_canvas_w + px] == target) { + if (!in_span && sp < STACK_MAX) { + g_canvas[ny * g_canvas_w + px] = fill_px; + stack[sp++] = {(int16_t)px, (int16_t)ny}; + in_span = true; + } + } else { + in_span = false; + } + } + } + } + + montauk::mfree(stack); +} diff --git a/programs/src/paint/helpers.cpp b/programs/src/paint/helpers.cpp new file mode 100644 index 0000000..f47aeb7 --- /dev/null +++ b/programs/src/paint/helpers.cpp @@ -0,0 +1,85 @@ +/* + * helpers.cpp + * Pixel drawing helpers for Paint app + * Copyright (c) 2026 Daniel Hammer + */ + +#include "paint.h" + +void px_fill(uint32_t* px, int bw, int bh, + int x, int y, int w, int h, Color c) { + uint32_t v = c.to_pixel(); + int x0 = x < 0 ? 0 : x, y0 = y < 0 ? 0 : y; + int x1 = x + w > bw ? bw : x + w; + int y1 = y + h > bh ? bh : y + h; + for (int row = y0; row < y1; row++) + for (int col = x0; col < x1; col++) + px[row * bw + col] = v; +} + +void px_hline(uint32_t* px, int bw, int bh, + int x, int y, int w, Color c) { + if (y < 0 || y >= bh) return; + uint32_t v = c.to_pixel(); + int x0 = x < 0 ? 0 : x; + int x1 = x + w > bw ? bw : x + w; + for (int col = x0; col < x1; col++) + px[y * bw + col] = v; +} + +void px_vline(uint32_t* px, int bw, int bh, + int x, int y, int h, Color c) { + if (x < 0 || x >= bw) return; + uint32_t v = c.to_pixel(); + int y0 = y < 0 ? 0 : y; + int y1 = y + h > bh ? bh : y + h; + for (int row = y0; row < y1; row++) + px[row * bw + x] = v; +} + +void px_rect(uint32_t* px, int bw, int bh, + int x, int y, int w, int h, Color c) { + px_hline(px, bw, bh, x, y, w, c); + px_hline(px, bw, bh, x, y + h - 1, w, c); + px_vline(px, bw, bh, x, y, h, c); + px_vline(px, bw, bh, x + w - 1, y, h, c); +} + +void px_fill_rounded(uint32_t* px, int bw, int bh, + int x, int y, int w, int h, int r, Color c) { + uint32_t v = c.to_pixel(); + for (int row = 0; row < h; row++) { + int py = y + row; + if (py < 0 || py >= bh) continue; + int inset = 0; + if (row < r) { + int dy = r - 1 - row; + if (r == 3) { + if (dy >= 2) inset = 2; + else if (dy >= 1) inset = 1; + } else { + for (int i = r; i > 0; i--) { + int dx = r - i; + if (dx * dx + dy * dy < r * r) { inset = i; break; } + } + } + } else if (row >= h - r) { + int dy = row - (h - r); + if (r == 3) { + if (dy >= 2) inset = 2; + else if (dy >= 1) inset = 1; + } else { + for (int i = r; i > 0; i--) { + int dx = r - i; + if (dx * dx + dy * dy < r * r) { inset = i; break; } + } + } + } + int x0 = x + inset; + int x1 = x + w - inset; + if (x0 < 0) x0 = 0; + if (x1 > bw) x1 = bw; + for (int col = x0; col < x1; col++) + px[py * bw + col] = v; + } +} diff --git a/programs/src/paint/main.cpp b/programs/src/paint/main.cpp new file mode 100644 index 0000000..0bec453 --- /dev/null +++ b/programs/src/paint/main.cpp @@ -0,0 +1,486 @@ +/* + * main.cpp + * Paint app -- global state, event loop, entry point + * Copyright (c) 2026 Daniel Hammer + */ + +#include "paint.h" + +// ============================================================================ +// Global state definitions +// ============================================================================ + +int g_win_w = INIT_W; +int g_win_h = INIT_H; + +uint32_t* g_canvas = nullptr; +int g_canvas_w = 640; +int g_canvas_h = 480; + +uint32_t* g_undo_buf[UNDO_MAX]; +int g_undo_count = 0; +int g_undo_pos = 0; + +int g_scroll_x = 0; +int g_scroll_y = 0; + +Tool g_tool = TOOL_PENCIL; +Color g_fg_color = Color::from_rgb(0x00, 0x00, 0x00); +Color g_bg_color = Color::from_rgb(0xFF, 0xFF, 0xFF); +int g_brush_idx = 0; + +bool g_drawing = false; +int g_draw_x0 = 0, g_draw_y0 = 0; +int g_draw_x1 = 0, g_draw_y1 = 0; +int g_prev_x = 0, g_prev_y = 0; + +TrueTypeFont* g_font = nullptr; + +bool g_modified = false; +char g_filepath[256] = {}; + +// ============================================================================ +// Helpers +// ============================================================================ + +int brush_size() { + return BRUSH_SIZES[g_brush_idx]; +} + +int canvas_x() { + if (g_canvas_w < g_win_w) + return (g_win_w - g_canvas_w) / 2 - g_scroll_x; + return -g_scroll_x; +} + +int canvas_y() { + int area_y = TOOLBAR_H + COLOR_BAR_H; + int area_h = g_win_h - area_y - STATUS_BAR_H; + if (g_canvas_h < area_h) + return area_y + (area_h - g_canvas_h) / 2 - g_scroll_y; + return area_y - g_scroll_y; +} + +bool screen_to_canvas(int sx, int sy, int* cx, int* cy) { + *cx = sx - canvas_x(); + *cy = sy - canvas_y(); + return *cx >= 0 && *cx < g_canvas_w && *cy >= 0 && *cy < g_canvas_h; +} + +// ============================================================================ +// Undo/Redo +// ============================================================================ + +void undo_push() { + // Discard any redo states after current position + for (int i = g_undo_pos; i < g_undo_count; i++) { + if (g_undo_buf[i]) { + montauk::mfree(g_undo_buf[i]); + g_undo_buf[i] = nullptr; + } + } + g_undo_count = g_undo_pos; + + // If at capacity, shift everything down + if (g_undo_count >= UNDO_MAX) { + if (g_undo_buf[0]) montauk::mfree(g_undo_buf[0]); + for (int i = 1; i < UNDO_MAX; i++) + g_undo_buf[i - 1] = g_undo_buf[i]; + g_undo_buf[UNDO_MAX - 1] = nullptr; + g_undo_count = UNDO_MAX - 1; + g_undo_pos = g_undo_count; + } + + int sz = g_canvas_w * g_canvas_h * 4; + uint32_t* buf = (uint32_t*)montauk::malloc(sz); + if (buf) { + montauk::memcpy(buf, g_canvas, sz); + g_undo_buf[g_undo_count] = buf; + g_undo_count++; + g_undo_pos = g_undo_count; + } +} + +void undo_do() { + if (g_undo_pos <= 0) return; + // Save current state as redo if we're at the top + if (g_undo_pos == g_undo_count && g_undo_count < UNDO_MAX) { + int sz = g_canvas_w * g_canvas_h * 4; + uint32_t* buf = (uint32_t*)montauk::malloc(sz); + if (buf) { + montauk::memcpy(buf, g_canvas, sz); + g_undo_buf[g_undo_count] = buf; + g_undo_count++; + } + } + g_undo_pos--; + int sz = g_canvas_w * g_canvas_h * 4; + montauk::memcpy(g_canvas, g_undo_buf[g_undo_pos], sz); +} + +void redo_do() { + if (g_undo_pos >= g_undo_count - 1) return; + g_undo_pos++; + int sz = g_canvas_w * g_canvas_h * 4; + montauk::memcpy(g_canvas, g_undo_buf[g_undo_pos], sz); +} + +// ============================================================================ +// Toolbar hit testing +// ============================================================================ + +static bool handle_toolbar_click(int mx, int my) { + if (my >= TOOLBAR_H) return false; + + // Walk the button layout to find which button was clicked + int bx = 4; + for (int i = 0; i < TOOL_COUNT; i++) { + int w = 48; + int x1 = bx + w; + if (mx >= bx && mx < x1) { + g_tool = (Tool)i; + return true; + } + bx = x1 + 4; + if (i == TOOL_ERASER || i == TOOL_FILLED_ELLIPSE || i == TOOL_EYEDROPPER) + bx += 8; // separator + } + + // Brush size button + { + int w = 40; + int x1 = bx + w; + if (mx >= bx && mx < x1) { + g_brush_idx = (g_brush_idx + 1) % BRUSH_SIZE_COUNT; + return true; + } + } + + return false; +} + +// ============================================================================ +// Color bar hit testing +// ============================================================================ + +static bool handle_colorbar_click(int mx, int my, bool right_click) { + int cbar_y = TOOLBAR_H; + if (my < cbar_y || my >= cbar_y + COLOR_BAR_H) return false; + + int preview_sz = COLOR_BAR_H - 8; + int sw_x = 4 + preview_sz + 16; + + for (int i = 0; i < PALETTE_COUNT; i++) { + int row = i >= 14 ? 1 : 0; + int col = i >= 14 ? i - 14 : i; + int sx = sw_x + col * (SWATCH_SIZE + 2); + int sy = cbar_y + 2 + row * (SWATCH_SIZE / 2 + 1); + int sh = SWATCH_SIZE / 2; + + if (mx >= sx && mx < sx + SWATCH_SIZE && my >= sy && my < sy + sh) { + if (right_click) + g_bg_color = PALETTE[i]; + else + g_fg_color = PALETTE[i]; + return true; + } + } + + return false; +} + +// ============================================================================ +// Scroll clamping +// ============================================================================ + +static void clamp_scroll() { + int area_h = g_win_h - TOOLBAR_H - COLOR_BAR_H - STATUS_BAR_H; + int max_sx = g_canvas_w - g_win_w + 40; + int max_sy = g_canvas_h - area_h + 40; + if (max_sx < 0) max_sx = 0; + if (max_sy < 0) max_sy = 0; + if (g_scroll_x < 0) g_scroll_x = 0; + if (g_scroll_x > max_sx) g_scroll_x = max_sx; + if (g_scroll_y < 0) g_scroll_y = 0; + if (g_scroll_y > max_sy) g_scroll_y = max_sy; +} + +// ============================================================================ +// Apply shape tool (commit line/rect/ellipse to canvas) +// ============================================================================ + +static void apply_shape() { + int bs = brush_size(); + Color c = g_fg_color; + + switch (g_tool) { + case TOOL_LINE: + canvas_draw_line(g_draw_x0, g_draw_y0, g_draw_x1, g_draw_y1, c, bs); + break; + case TOOL_RECT: + canvas_draw_rect(g_draw_x0, g_draw_y0, g_draw_x1, g_draw_y1, c, bs); + break; + case TOOL_FILLED_RECT: + canvas_fill_rect(g_draw_x0, g_draw_y0, g_draw_x1, g_draw_y1, c); + break; + case TOOL_ELLIPSE: + canvas_draw_ellipse(g_draw_x0, g_draw_y0, g_draw_x1, g_draw_y1, c, bs); + break; + case TOOL_FILLED_ELLIPSE: + canvas_fill_ellipse(g_draw_x0, g_draw_y0, g_draw_x1, g_draw_y1, c); + break; + default: + break; + } +} + +// ============================================================================ +// Entry point +// ============================================================================ + +extern "C" void _start() { + // Initialize undo pointers + for (int i = 0; i < UNDO_MAX; i++) g_undo_buf[i] = nullptr; + + // Allocate canvas + int canvas_bytes = g_canvas_w * g_canvas_h * 4; + g_canvas = (uint32_t*)montauk::malloc(canvas_bytes); + if (!g_canvas) montauk::exit(1); + canvas_clear(g_bg_color); + + // Load font + g_font = (TrueTypeFont*)montauk::malloc(sizeof(TrueTypeFont)); + if (g_font) { + montauk::memset(g_font, 0, sizeof(TrueTypeFont)); + if (!g_font->init("0:/fonts/Roboto-Medium.ttf")) { + montauk::mfree(g_font); + g_font = nullptr; + } + } + + // Push initial undo state + undo_push(); + + // Create window + Montauk::WinCreateResult wres; + if (montauk::win_create("Paint", INIT_W, INIT_H, &wres) < 0 || wres.id < 0) + montauk::exit(1); + + int win_id = wres.id; + uint32_t* pixels = (uint32_t*)(uintptr_t)wres.pixelVa; + + render(pixels); + montauk::win_present(win_id); + + while (true) { + Montauk::WinEvent ev; + int r = montauk::win_poll(win_id, &ev); + + if (r < 0) break; + + if (r == 0) { + montauk::sleep_ms(16); + continue; + } + + // Close + if (ev.type == 3) break; + + // Resize + if (ev.type == 2) { + g_win_w = ev.resize.w; + g_win_h = ev.resize.h; + pixels = (uint32_t*)(uintptr_t)montauk::win_resize(win_id, g_win_w, g_win_h); + clamp_scroll(); + render(pixels); + montauk::win_present(win_id); + continue; + } + + bool redraw = false; + + // ============================================================ + // Keyboard + // ============================================================ + if (ev.type == 0 && ev.key.pressed) { + auto& key = ev.key; + + // Ctrl+Z: undo + if (key.ctrl && (key.ascii == 'z' || key.ascii == 'Z')) { + undo_do(); + redraw = true; + } + // Ctrl+Y: redo + else if (key.ctrl && (key.ascii == 'y' || key.ascii == 'Y')) { + redo_do(); + redraw = true; + } + // Ctrl+N: new canvas (clear) + else if (key.ctrl && (key.ascii == 'n' || key.ascii == 'N')) { + undo_push(); + canvas_clear(g_bg_color); + g_modified = false; + redraw = true; + } + // Tool shortcuts + else if (!key.ctrl) { + switch (key.ascii) { + case 'p': case 'P': g_tool = TOOL_PENCIL; redraw = true; break; + case 'b': case 'B': g_tool = TOOL_BRUSH; redraw = true; break; + case 'e': case 'E': g_tool = TOOL_ERASER; redraw = true; break; + case 'l': case 'L': g_tool = TOOL_LINE; redraw = true; break; + case 'r': case 'R': g_tool = TOOL_RECT; redraw = true; break; + case 'o': case 'O': g_tool = TOOL_ELLIPSE; redraw = true; break; + case 'f': case 'F': g_tool = TOOL_FILL; redraw = true; break; + case 'i': case 'I': g_tool = TOOL_EYEDROPPER; redraw = true; break; + case '[': + if (g_brush_idx > 0) { g_brush_idx--; redraw = true; } + break; + case ']': + if (g_brush_idx < BRUSH_SIZE_COUNT - 1) { g_brush_idx++; redraw = true; } + break; + default: break; + } + } + // Escape: cancel shape drawing + if (key.scancode == 0x01) { + if (g_drawing) { + g_drawing = false; + redraw = true; + } + } + } + + // ============================================================ + // Mouse + // ============================================================ + if (ev.type == 1) { + int mx = ev.mouse.x; + int my = ev.mouse.y; + uint8_t btns = ev.mouse.buttons; + uint8_t prev = ev.mouse.prev_buttons; + bool left_click = (btns & 1) && !(prev & 1); + bool left_held = (btns & 1); + bool left_released = !(btns & 1) && (prev & 1); + bool right_click = (btns & 2) && !(prev & 2); + + // Scroll + if (ev.mouse.scroll != 0) { + g_scroll_y -= ev.mouse.scroll * 30; + clamp_scroll(); + redraw = true; + } + + // Toolbar click + if (left_click && my < TOOLBAR_H) { + if (handle_toolbar_click(mx, my)) + redraw = true; + goto done_mouse; + } + + // Color bar click + if ((left_click || right_click) && my >= TOOLBAR_H && my < TOOLBAR_H + COLOR_BAR_H) { + if (handle_colorbar_click(mx, my, right_click)) + redraw = true; + goto done_mouse; + } + + // Canvas interaction + { + int cx_pos, cy_pos; + bool on_canvas = screen_to_canvas(mx, my, &cx_pos, &cy_pos); + + // Eyedropper + if (g_tool == TOOL_EYEDROPPER && left_click && on_canvas) { + uint32_t px = g_canvas[cy_pos * g_canvas_w + cx_pos]; + g_fg_color = Color::from_rgb((px >> 16) & 0xFF, (px >> 8) & 0xFF, px & 0xFF); + redraw = true; + goto done_mouse; + } + + // Fill tool + if (g_tool == TOOL_FILL && left_click && on_canvas) { + undo_push(); + canvas_flood_fill(cx_pos, cy_pos, g_fg_color); + g_modified = true; + redraw = true; + goto done_mouse; + } + + // Pencil / Brush / Eraser: freehand drawing + if ((g_tool == TOOL_PENCIL || g_tool == TOOL_BRUSH || g_tool == TOOL_ERASER)) { + Color draw_c = (g_tool == TOOL_ERASER) ? g_bg_color : g_fg_color; + int bs = brush_size(); + if (g_tool == TOOL_PENCIL) bs = 1; + if (g_tool == TOOL_BRUSH) { + if (bs < 4) bs = 4; + } + + if (left_click && on_canvas) { + undo_push(); + g_drawing = true; + g_prev_x = cx_pos; + g_prev_y = cy_pos; + canvas_draw_brush(cx_pos, cy_pos, draw_c, bs); + g_modified = true; + redraw = true; + } else if (g_drawing && left_held) { + if (on_canvas && (cx_pos != g_prev_x || cy_pos != g_prev_y)) { + canvas_draw_line(g_prev_x, g_prev_y, cx_pos, cy_pos, draw_c, bs); + g_prev_x = cx_pos; + g_prev_y = cy_pos; + redraw = true; + } + } + if (left_released && g_drawing) { + g_drawing = false; + redraw = true; + } + goto done_mouse; + } + + // Shape tools: line, rect, ellipse + if (g_tool == TOOL_LINE || g_tool == TOOL_RECT || g_tool == TOOL_FILLED_RECT || + g_tool == TOOL_ELLIPSE || g_tool == TOOL_FILLED_ELLIPSE) { + + if (left_click && on_canvas) { + undo_push(); + g_drawing = true; + g_draw_x0 = cx_pos; + g_draw_y0 = cy_pos; + g_draw_x1 = cx_pos; + g_draw_y1 = cy_pos; + redraw = true; + } else if (g_drawing && left_held) { + if (on_canvas) { + g_draw_x1 = cx_pos; + g_draw_y1 = cy_pos; + redraw = true; + } + } + if (left_released && g_drawing) { + if (on_canvas) { + g_draw_x1 = cx_pos; + g_draw_y1 = cy_pos; + } + apply_shape(); + g_drawing = false; + g_modified = true; + redraw = true; + } + goto done_mouse; + } + } + + done_mouse:; + } + + if (redraw) { + render(pixels); + montauk::win_present(win_id); + } + } + + montauk::win_destroy(win_id); + montauk::exit(0); +} diff --git a/programs/src/paint/manifest.toml b/programs/src/paint/manifest.toml new file mode 100644 index 0000000..eabab12 --- /dev/null +++ b/programs/src/paint/manifest.toml @@ -0,0 +1,8 @@ +[app] +name = "Paint" +binary = "paint.elf" +icon = "paint.svg" + +[menu] +category = "Applications" +visible = true diff --git a/programs/src/paint/paint.h b/programs/src/paint/paint.h new file mode 100644 index 0000000..1518233 --- /dev/null +++ b/programs/src/paint/paint.h @@ -0,0 +1,198 @@ +/* + * paint.h + * Shared header for the MontaukOS Paint app + * Copyright (c) 2026 Daniel Hammer + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +extern "C" { +#include +#include +} + +using namespace gui; + +// ============================================================================ +// Constants +// ============================================================================ + +static constexpr int INIT_W = 800; +static constexpr int INIT_H = 600; +static constexpr int TOOLBAR_H = 36; +static constexpr int TB_BTN_SIZE = 24; +static constexpr int TB_BTN_Y = 6; +static constexpr int TB_BTN_RAD = 3; +static constexpr int STATUS_BAR_H = 24; +static constexpr int COLOR_BAR_H = 36; + +static constexpr int SWATCH_SIZE = 20; +static constexpr int SWATCH_PAD = 4; +static constexpr int SWATCH_Y = 8; + +static constexpr int MAX_CANVAS_W = 2048; +static constexpr int MAX_CANVAS_H = 2048; + +static constexpr int FONT_SIZE = 16; + +// UI colors +static constexpr Color BG_COLOR = Color::from_rgb(0xE0, 0xE0, 0xE0); +static constexpr Color TOOLBAR_BG = Color::from_rgb(0xF5, 0xF5, 0xF5); +static constexpr Color TB_BTN_BG = Color::from_rgb(0xE8, 0xE8, 0xE8); +static constexpr Color TB_BTN_ACTIVE = Color::from_rgb(0xC0, 0xD0, 0xE8); +static constexpr Color TB_SEP_COLOR = Color::from_rgb(0xCC, 0xCC, 0xCC); +static constexpr Color HEADER_TEXT = Color::from_rgb(0x55, 0x55, 0x55); +static constexpr Color STATUS_BG = Color::from_rgb(0x2B, 0x3E, 0x50); +static constexpr Color STATUS_TEXT = Color::from_rgb(0xFF, 0xFF, 0xFF); +static constexpr Color CANVAS_BORDER = Color::from_rgb(0x99, 0x99, 0x99); +static constexpr Color SELECT_BORDER = Color::from_rgb(0x36, 0x7B, 0xF0); + +// ============================================================================ +// Tool types +// ============================================================================ + +enum Tool : uint8_t { + TOOL_PENCIL = 0, + TOOL_BRUSH, + TOOL_ERASER, + TOOL_LINE, + TOOL_RECT, + TOOL_FILLED_RECT, + TOOL_ELLIPSE, + TOOL_FILLED_ELLIPSE, + TOOL_FILL, + TOOL_EYEDROPPER, + TOOL_COUNT +}; + +// ============================================================================ +// Palette colors +// ============================================================================ + +static constexpr int PALETTE_COUNT = 28; +static constexpr Color PALETTE[PALETTE_COUNT] = { + // Row 1: basic colors + Color::from_rgb(0x00, 0x00, 0x00), // Black + Color::from_rgb(0x7F, 0x7F, 0x7F), // Gray + Color::from_rgb(0x88, 0x00, 0x15), // Dark red + Color::from_rgb(0xED, 0x1C, 0x24), // Red + Color::from_rgb(0xFF, 0x7F, 0x27), // Orange + Color::from_rgb(0xFF, 0xF2, 0x00), // Yellow + Color::from_rgb(0x22, 0xB1, 0x4C), // Green + Color::from_rgb(0x00, 0xA2, 0xE8), // Light blue + Color::from_rgb(0x3F, 0x48, 0xCC), // Blue + Color::from_rgb(0xA3, 0x49, 0xA4), // Purple + Color::from_rgb(0xB9, 0x7A, 0x57), // Brown + Color::from_rgb(0xFF, 0xAE, 0xC9), // Pink + Color::from_rgb(0xB5, 0xE6, 0x1D), // Lime + Color::from_rgb(0x99, 0xD9, 0xEA), // Sky + // Row 2: lighter variants and white + Color::from_rgb(0xFF, 0xFF, 0xFF), // White + Color::from_rgb(0xC3, 0xC3, 0xC3), // Light gray + Color::from_rgb(0xB9, 0x5B, 0x5B), // Salmon + Color::from_rgb(0xFF, 0xC9, 0x0E), // Gold + Color::from_rgb(0xFE, 0xF0, 0x82), // Light yellow + Color::from_rgb(0xA8, 0xE6, 0x1D), // Bright lime + Color::from_rgb(0x70, 0xDB, 0x93), // Sea green + Color::from_rgb(0x7E, 0xC8, 0xE3), // Powder blue + Color::from_rgb(0x00, 0x78, 0xD7), // Bright blue + Color::from_rgb(0xC8, 0xBF, 0xE7), // Lavender + Color::from_rgb(0xD9, 0x9E, 0x82), // Tan + Color::from_rgb(0xDE, 0xCE, 0xEF), // Light lavender + Color::from_rgb(0xE0, 0xE0, 0xD0), // Cream + Color::from_rgb(0xF0, 0xD0, 0xB0), // Peach +}; + +// ============================================================================ +// Brush sizes +// ============================================================================ + +static constexpr int BRUSH_SIZES[] = { 1, 2, 4, 8, 12, 20 }; +static constexpr int BRUSH_SIZE_COUNT = 6; + +// ============================================================================ +// Global state (extern -- defined in main.cpp) +// ============================================================================ + +extern int g_win_w, g_win_h; + +// Canvas +extern uint32_t* g_canvas; +extern int g_canvas_w, g_canvas_h; + +// Undo +static constexpr int UNDO_MAX = 16; +extern uint32_t* g_undo_buf[UNDO_MAX]; +extern int g_undo_count; +extern int g_undo_pos; + +// View +extern int g_scroll_x, g_scroll_y; + +// Tool state +extern Tool g_tool; +extern Color g_fg_color; +extern Color g_bg_color; +extern int g_brush_idx; + +// Drawing state +extern bool g_drawing; +extern int g_draw_x0, g_draw_y0; +extern int g_draw_x1, g_draw_y1; +extern int g_prev_x, g_prev_y; + +// Font +extern TrueTypeFont* g_font; + +// Modified flag +extern bool g_modified; +extern char g_filepath[256]; + +// ============================================================================ +// Function declarations -- helpers.cpp +// ============================================================================ + +void px_fill(uint32_t* px, int bw, int bh, int x, int y, int w, int h, Color c); +void px_hline(uint32_t* px, int bw, int bh, int x, int y, int w, Color c); +void px_vline(uint32_t* px, int bw, int bh, int x, int y, int h, Color c); +void px_rect(uint32_t* px, int bw, int bh, int x, int y, int w, int h, Color c); +void px_fill_rounded(uint32_t* px, int bw, int bh, int x, int y, int w, int h, int r, Color c); + +// ============================================================================ +// Function declarations -- drawing.cpp +// ============================================================================ + +void canvas_put_pixel(int x, int y, Color c); +void canvas_draw_line(int x0, int y0, int x1, int y1, Color c, int thickness); +void canvas_draw_rect(int x0, int y0, int x1, int y1, Color c, int thickness); +void canvas_fill_rect(int x0, int y0, int x1, int y1, Color c); +void canvas_draw_ellipse(int x0, int y0, int x1, int y1, Color c, int thickness); +void canvas_fill_ellipse(int x0, int y0, int x1, int y1, Color c); +void canvas_flood_fill(int x, int y, Color fill_color); +void canvas_draw_brush(int x, int y, Color c, int size); +void canvas_clear(Color c); + +// ============================================================================ +// Function declarations -- render.cpp +// ============================================================================ + +void render(uint32_t* pixels); + +// ============================================================================ +// Function declarations -- main.cpp +// ============================================================================ + +void undo_push(); +void undo_do(); +void redo_do(); +int canvas_x(); +int canvas_y(); +bool screen_to_canvas(int sx, int sy, int* cx, int* cy); +int brush_size(); diff --git a/programs/src/paint/render.cpp b/programs/src/paint/render.cpp new file mode 100644 index 0000000..6cbb01b --- /dev/null +++ b/programs/src/paint/render.cpp @@ -0,0 +1,204 @@ +/* + * render.cpp + * Rendering -- toolbar, canvas, color bar, status bar + * Copyright (c) 2026 Daniel Hammer + */ + +#include "paint.h" + +static const char* tool_names[TOOL_COUNT] = { + "Pencil", "Brush", "Eraser", "Line", + "Rect", "FRect", "Ellipse", "FEllip", + "Fill", "Pick" +}; + +void render(uint32_t* pixels) { + px_fill(pixels, g_win_w, g_win_h, 0, 0, g_win_w, g_win_h, BG_COLOR); + + // ================================================================ + // Toolbar + // ================================================================ + px_fill(pixels, g_win_w, g_win_h, 0, 0, g_win_w, TOOLBAR_H, TOOLBAR_BG); + px_hline(pixels, g_win_w, g_win_h, 0, TOOLBAR_H - 1, g_win_w, TB_SEP_COLOR); + + int bx = 4; + auto tb_btn = [&](int w, bool active, const char* label) { + Color bg = active ? TB_BTN_ACTIVE : TB_BTN_BG; + px_fill_rounded(pixels, g_win_w, g_win_h, bx, TB_BTN_Y, w, TB_BTN_SIZE, TB_BTN_RAD, bg); + if (g_font && label[0]) { + int tw = g_font->measure_text(label, FONT_SIZE); + g_font->draw_to_buffer(pixels, g_win_w, g_win_h, + bx + (w - tw) / 2, TB_BTN_Y + (TB_BTN_SIZE - FONT_SIZE) / 2, + label, HEADER_TEXT, FONT_SIZE); + } + bx += w + 4; + }; + auto tb_sep = [&]() { + px_vline(pixels, g_win_w, g_win_h, bx, 6, TOOLBAR_H - 12, TB_SEP_COLOR); + bx += 8; + }; + + // Tool buttons + for (int i = 0; i < TOOL_COUNT; i++) { + int w = 48; + if (i == TOOL_FILLED_RECT || i == TOOL_FILLED_ELLIPSE) w = 48; + tb_btn(w, g_tool == (Tool)i, tool_names[i]); + if (i == TOOL_ERASER || i == TOOL_FILLED_ELLIPSE || i == TOOL_EYEDROPPER) + tb_sep(); + } + + // Brush size indicator + { + int bs = brush_size(); + char sz_label[16]; + snprintf(sz_label, 16, "%dpx", bs); + tb_btn(40, false, sz_label); + } + + // ================================================================ + // Color bar (below toolbar) + // ================================================================ + int cbar_y = TOOLBAR_H; + px_fill(pixels, g_win_w, g_win_h, 0, cbar_y, g_win_w, COLOR_BAR_H, TOOLBAR_BG); + px_hline(pixels, g_win_w, g_win_h, 0, cbar_y + COLOR_BAR_H - 1, g_win_w, TB_SEP_COLOR); + + // FG/BG color preview + int preview_x = 4; + int preview_y = cbar_y + 4; + int preview_sz = COLOR_BAR_H - 8; + + // BG behind (offset right-down) + px_fill(pixels, g_win_w, g_win_h, preview_x + 10, preview_y + 6, preview_sz - 4, preview_sz - 4, g_bg_color); + px_rect(pixels, g_win_w, g_win_h, preview_x + 10, preview_y + 6, preview_sz - 4, preview_sz - 4, Color::from_rgb(0x80, 0x80, 0x80)); + // FG in front (offset left-up) + px_fill(pixels, g_win_w, g_win_h, preview_x, preview_y, preview_sz - 4, preview_sz - 4, g_fg_color); + px_rect(pixels, g_win_w, g_win_h, preview_x, preview_y, preview_sz - 4, preview_sz - 4, Color::from_rgb(0x80, 0x80, 0x80)); + + // Palette swatches + int sw_x = preview_x + preview_sz + 16; + for (int i = 0; i < PALETTE_COUNT; i++) { + int row = i >= 14 ? 1 : 0; + int col = i >= 14 ? i - 14 : i; + int sx = sw_x + col * (SWATCH_SIZE + 2); + int sy = cbar_y + 2 + row * (SWATCH_SIZE / 2 + 1); + int sh = SWATCH_SIZE / 2; + + px_fill(pixels, g_win_w, g_win_h, sx, sy, SWATCH_SIZE, sh, PALETTE[i]); + + // Highlight if selected + bool is_fg = (PALETTE[i].r == g_fg_color.r && PALETTE[i].g == g_fg_color.g && PALETTE[i].b == g_fg_color.b); + bool is_bg = (PALETTE[i].r == g_bg_color.r && PALETTE[i].g == g_bg_color.g && PALETTE[i].b == g_bg_color.b); + if (is_fg) + px_rect(pixels, g_win_w, g_win_h, sx - 1, sy - 1, SWATCH_SIZE + 2, sh + 2, SELECT_BORDER); + else if (is_bg) + px_rect(pixels, g_win_w, g_win_h, sx - 1, sy - 1, SWATCH_SIZE + 2, sh + 2, Color::from_rgb(0x99, 0x99, 0x99)); + } + + // ================================================================ + // Canvas area + // ================================================================ + int area_y = TOOLBAR_H + COLOR_BAR_H; + + // Canvas position (centered in area if smaller, otherwise scrolled) + int cx = canvas_x(); + int cy = canvas_y(); + + // Draw canvas border + px_rect(pixels, g_win_w, g_win_h, cx - 1, cy - 1, g_canvas_w + 2, g_canvas_h + 2, CANVAS_BORDER); + + // Blit canvas to screen with clipping + int clip_x0 = 0; + int clip_y0 = area_y; + int clip_x1 = g_win_w; + int clip_y1 = g_win_h - STATUS_BAR_H; + + for (int row = 0; row < g_canvas_h; row++) { + int sy = cy + row; + if (sy < clip_y0 || sy >= clip_y1) continue; + for (int col = 0; col < g_canvas_w; col++) { + int sx = cx + col; + if (sx < clip_x0 || sx >= clip_x1) continue; + pixels[sy * g_win_w + sx] = g_canvas[row * g_canvas_w + col]; + } + } + + // Shape preview overlay (for line/rect/ellipse tools while dragging) + if (g_drawing && (g_tool == TOOL_LINE || g_tool == TOOL_RECT || g_tool == TOOL_FILLED_RECT || + g_tool == TOOL_ELLIPSE || g_tool == TOOL_FILLED_ELLIPSE)) { + // Draw preview directly on screen pixels using canvas coords mapped to screen + int sx0 = cx + g_draw_x0; + int sy0 = cy + g_draw_y0; + int sx1 = cx + g_draw_x1; + int sy1 = cy + g_draw_y1; + + // Simple preview: draw XOR-style dashed outline + int rx0 = sx0 < sx1 ? sx0 : sx1; + int ry0 = sy0 < sy1 ? sy0 : sy1; + int rx1 = sx0 > sx1 ? sx0 : sx1; + int ry1 = sy0 > sy1 ? sy0 : sy1; + + Color preview_c = Color::from_rgb(0x80, 0x80, 0x80); + if (g_tool == TOOL_LINE) { + // Dashed line preview + int dx = sx1 - sx0, dy = sy1 - sy0; + int adx = dx < 0 ? -dx : dx; + int ady = dy < 0 ? -dy : dy; + int step_x = dx < 0 ? -1 : 1; + int step_y = dy < 0 ? -1 : 1; + int err = adx - ady; + int lx = sx0, ly = sy0; + int cnt = 0; + while (true) { + if ((cnt / 4) % 2 == 0 && + lx >= clip_x0 && lx < clip_x1 && ly >= clip_y0 && ly < clip_y1) + pixels[ly * g_win_w + lx] = preview_c.to_pixel(); + if (lx == sx1 && ly == sy1) break; + int e2 = 2 * err; + if (e2 > -ady) { err -= ady; lx += step_x; } + if (e2 < adx) { err += adx; ly += step_y; } + cnt++; + } + } else { + // Dashed rectangle/ellipse outline + for (int x = rx0; x <= rx1; x++) { + if (((x - rx0) / 4) % 2 == 0) { + if (ry0 >= clip_y0 && ry0 < clip_y1 && x >= clip_x0 && x < clip_x1) + pixels[ry0 * g_win_w + x] = preview_c.to_pixel(); + if (ry1 >= clip_y0 && ry1 < clip_y1 && x >= clip_x0 && x < clip_x1) + pixels[ry1 * g_win_w + x] = preview_c.to_pixel(); + } + } + for (int y = ry0; y <= ry1; y++) { + if (((y - ry0) / 4) % 2 == 0) { + if (rx0 >= clip_x0 && rx0 < clip_x1 && y >= clip_y0 && y < clip_y1) + pixels[y * g_win_w + rx0] = preview_c.to_pixel(); + if (rx1 >= clip_x0 && rx1 < clip_x1 && y >= clip_y0 && y < clip_y1) + pixels[y * g_win_w + rx1] = preview_c.to_pixel(); + } + } + } + } + + // ================================================================ + // Status bar + // ================================================================ + int sy = g_win_h - STATUS_BAR_H; + px_fill(pixels, g_win_w, g_win_h, 0, sy, g_win_w, STATUS_BAR_H, STATUS_BG); + + if (g_font) { + char status[128]; + snprintf(status, 128, " %s - %dx%d", tool_names[g_tool], g_canvas_w, g_canvas_h); + int sty = sy + (STATUS_BAR_H - FONT_SIZE) / 2; + g_font->draw_to_buffer(pixels, g_win_w, g_win_h, 6, sty, status, STATUS_TEXT, FONT_SIZE); + + // Right side: cursor position if on canvas + char right[64]; + if (g_drawing) { + snprintf(right, 64, "(%d, %d) ", g_draw_x1, g_draw_y1); + } else { + snprintf(right, 64, "%s ", g_modified ? "Modified" : ""); + } + int rw = g_font->measure_text(right, FONT_SIZE); + g_font->draw_to_buffer(pixels, g_win_w, g_win_h, g_win_w - rw - 6, sty, right, STATUS_TEXT, FONT_SIZE); + } +} diff --git a/programs/src/paint/stb_truetype_impl.cpp b/programs/src/paint/stb_truetype_impl.cpp new file mode 100644 index 0000000..9ce2266 --- /dev/null +++ b/programs/src/paint/stb_truetype_impl.cpp @@ -0,0 +1,35 @@ +/* + * stb_truetype_impl.cpp + * Single compilation unit for stb_truetype in MontaukOS freestanding environment + * Copyright (c) 2026 Daniel Hammer + */ + +#include +#include +#include +#include +#include + +// Override all stb_truetype dependencies before including the implementation + +#define STBTT_ifloor(x) ((int) stb_floor(x)) +#define STBTT_iceil(x) ((int) stb_ceil(x)) +#define STBTT_sqrt(x) stb_sqrt(x) +#define STBTT_pow(x,y) stb_pow(x,y) +#define STBTT_fmod(x,y) stb_fmod(x,y) +#define STBTT_cos(x) stb_cos(x) +#define STBTT_acos(x) stb_acos(x) +#define STBTT_fabs(x) stb_fabs(x) + +#define STBTT_malloc(x,u) ((void)(u), montauk::malloc(x)) +#define STBTT_free(x,u) ((void)(u), montauk::mfree(x)) + +#define STBTT_memcpy(d,s,n) montauk::memcpy(d,s,n) +#define STBTT_memset(d,v,n) montauk::memset(d,v,n) + +#define STBTT_strlen(x) montauk::slen(x) + +#define STBTT_assert(x) ((void)(x)) + +#define STB_TRUETYPE_IMPLEMENTATION +#include diff --git a/programs/src/shell/exec.cpp b/programs/src/shell/exec.cpp index e94dc9a..bfe7ed1 100644 --- a/programs/src/shell/exec.cpp +++ b/programs/src/shell/exec.cpp @@ -6,19 +6,36 @@ #include "shell.h" -// ---- Try to spawn an ELF at the given path ---- +// ---- Check if a file exists ---- -static bool try_exec(const char* path, const char* args) { +static bool file_exists(const char* path) { int h = montauk::open(path); if (h < 0) return false; montauk::close(h); + return true; +} +// ---- Try to spawn an ELF at the given path ---- + +static bool try_exec(const char* path, const char* args) { + if (!file_exists(path)) return false; int pid = montauk::spawn(path, args); if (pid < 0) return false; montauk::waitpid(pid); return true; } +// ---- Build an absolute path from CWD + relative name ---- + +static void build_cwd_path(const char* name, char* out, int outMax) { + build_drive_path(current_drive, "", out, outMax); + if (cwd[0]) { + scat(out, cwd, outMax); + scat(out, "/", outMax); + } + scat(out, name, outMax); +} + // ---- Resolve arguments: expand relative file paths against CWD ---- static void resolve_args(const char* args, char* out, int outMax) { @@ -46,7 +63,12 @@ static void resolve_args(const char* args, char* out, int outMax) { int j = 0; while (cwd[j] && r < 255) candidate[r++] = cwd[j++]; if (cwd[0] && r < 255) candidate[r++] = '/'; - for (int k = 0; k < tokLen && r < 255; k++) candidate[r++] = tokStart[k]; + + // Strip leading "./" from token + int skip = 0; + if (tokLen >= 2 && tokStart[0] == '.' && tokStart[1] == '/') skip = 2; + + for (int k = skip; k < tokLen && r < 255; k++) candidate[r++] = tokStart[k]; candidate[r] = '\0'; int h = montauk::open(candidate); @@ -82,38 +104,50 @@ int exec_external(const char* cmd, const char* args) { resolve_args(args, resolvedArgs, sizeof(resolvedArgs)); const char* finalArgs = resolvedArgs[0] ? resolvedArgs : nullptr; - // 1. Try 0:/os/.elf - scopy(path, "0:/os/", sizeof(path)); - scat(path, cmd, sizeof(path)); - scat(path, ".elf", sizeof(path)); - if (try_exec(path, finalArgs)) return 0; + // Strip leading "./" from command name + const char* name = cmd; + if (name[0] == '.' && name[1] == '/') name += 2; - // 2. Try 0:/games/.elf - scopy(path, "0:/games/", sizeof(path)); - scat(path, cmd, sizeof(path)); - scat(path, ".elf", sizeof(path)); - if (try_exec(path, finalArgs)) return 0; - - // 3. Try N://.elf on current drive - if (cwd[0]) { - build_drive_path(current_drive, "", path, sizeof(path)); - scat(path, cwd, sizeof(path)); - scat(path, "/", sizeof(path)); - scat(path, cmd, sizeof(path)); - scat(path, ".elf", sizeof(path)); - if (try_exec(path, finalArgs)) return 0; + // 0. If cmd has a drive prefix (absolute path), try it directly + if (has_drive_prefix(cmd)) { + if (try_exec(cmd, finalArgs)) return 0; + montauk::print(cmd); + montauk::print(": not found\n"); + return 127; } - // 4. Try N:/.elf on current drive - build_drive_path(current_drive, "", path, sizeof(path)); - scat(path, cmd, sizeof(path)); + // 1. Try as-is in CWD (exact name, e.g., "a.out" or "hello.elf") + build_cwd_path(name, path, sizeof(path)); + if (try_exec(path, finalArgs)) return 0; + + // 2. Try with .elf extension in CWD + build_cwd_path(name, path, sizeof(path)); scat(path, ".elf", sizeof(path)); if (try_exec(path, finalArgs)) return 0; - // 5. If on a non-zero drive, also try 0:/.elf + // 3. Try 0:/os/.elf + scopy(path, "0:/os/", sizeof(path)); + scat(path, name, sizeof(path)); + scat(path, ".elf", sizeof(path)); + if (try_exec(path, finalArgs)) return 0; + + // 4. Try 0:/os/ (no extension) + scopy(path, "0:/os/", sizeof(path)); + scat(path, name, sizeof(path)); + if (try_exec(path, finalArgs)) return 0; + + // 5. Try 0:/games/.elf + scopy(path, "0:/games/", sizeof(path)); + scat(path, name, sizeof(path)); + scat(path, ".elf", sizeof(path)); + if (try_exec(path, finalArgs)) return 0; + + // 6. If on a non-zero drive, also try drive root if (current_drive != 0) { - scopy(path, "0:/", sizeof(path)); - scat(path, cmd, sizeof(path)); + build_drive_path(current_drive, name, path, sizeof(path)); + if (try_exec(path, finalArgs)) return 0; + + build_drive_path(current_drive, name, path, sizeof(path)); scat(path, ".elf", sizeof(path)); if (try_exec(path, finalArgs)) return 0; } diff --git a/programs/src/spreadsheet/edit.cpp b/programs/src/spreadsheet/edit.cpp index 4c843a1..15da4f5 100644 --- a/programs/src/spreadsheet/edit.cpp +++ b/programs/src/spreadsheet/edit.cpp @@ -213,6 +213,62 @@ void apply_format(NumFormat f) { // Scroll clamping // ============================================================================ +// ============================================================================ +// Fill down (fill handle) +// ============================================================================ + +void fill_down(int src_r0, int src_c0, int src_r1, int src_c1, int dst_r1) { + if (dst_r1 <= src_r1) return; + if (dst_r1 >= MAX_ROWS) dst_r1 = MAX_ROWS - 1; + + undo_push(); + + int src_rows = src_r1 - src_r0 + 1; + + for (int r = src_r1 + 1; r <= dst_r1; r++) { + int src_r = src_r0 + ((r - src_r0) % src_rows); + int drow = r - src_r; + for (int c = src_c0; c <= src_c1; c++) { + Cell* src = &g_cells[src_r][c]; + Cell* dst = &g_cells[r][c]; + dst->align = src->align; + dst->fmt = src->fmt; + dst->bold = src->bold; + + if (src->input[0] == '=') { + // Formula: adjust cell references + adjust_formula_refs(src->input, dst->input, CELL_TEXT_MAX, 0, drow); + } else { + str_cpy(dst->input, src->input, CELL_TEXT_MAX); + } + } + } + + eval_all_cells(); + g_modified = true; +} + +// ============================================================================ +// Auto-fit column width +// ============================================================================ + +void auto_fit_column(int col) { + if (!g_font) return; + int max_w = MIN_COL_W; + for (int r = 0; r < MAX_ROWS; r++) { + if (g_cells[r][col].display[0]) { + TrueTypeFont* f = (g_cells[r][col].bold && g_font_bold) ? g_font_bold : g_font; + int tw = f->measure_text(g_cells[r][col].display, FONT_SIZE) + 12; + if (tw > max_w) max_w = tw; + } + } + g_col_widths[col] = max_w; +} + +// ============================================================================ +// Scroll clamping +// ============================================================================ + void clamp_scroll() { int pbh = g_pathbar_open ? PATHBAR_H : 0; int max_x = content_width() - (g_win_w - ROW_HEADER_W); diff --git a/programs/src/spreadsheet/formula.cpp b/programs/src/spreadsheet/formula.cpp index 4a27362..5eb73dc 100644 --- a/programs/src/spreadsheet/formula.cpp +++ b/programs/src/spreadsheet/formula.cpp @@ -6,6 +6,34 @@ #include "spreadsheet.h" +// ============================================================================ +// Formula name list (for autocomplete and parsing) +// ============================================================================ + +struct FormulaInfo { + const char* name; + const char* hint; +}; + +static const FormulaInfo g_formula_list[] = { + {"SUM", "SUM(range)"}, + {"AVG", "AVG(range)"}, + {"MIN", "MIN(range)"}, + {"MAX", "MAX(range)"}, + {"COUNT", "COUNT(range)"}, + {"ABS", "ABS(value)"}, + {"SQRT", "SQRT(value)"}, + {"ROUND", "ROUND(val,n)"}, + {"INT", "INT(value)"}, + {"FLOOR", "FLOOR(value)"}, + {"CEIL", "CEIL(value)"}, + {"POW", "POW(base,exp)"}, + {"MOD", "MOD(a,b)"}, + {"PI", "PI()"}, + {"IF", "IF(cond,t,f)"}, +}; +static constexpr int FORMULA_COUNT = sizeof(g_formula_list) / sizeof(g_formula_list[0]); + // ============================================================================ // Cell reference parsing // ============================================================================ @@ -124,6 +152,7 @@ static double eval_primary(const char* s, int* pos, bool* ok) { } fname[fi] = '\0'; + // Range functions: SUM, AVG, MIN, MAX, COUNT if (s[*pos] == '(' && (strcmp(fname, "SUM") == 0 || strcmp(fname, "AVG") == 0 || strcmp(fname, "MIN") == 0 || @@ -132,6 +161,77 @@ static double eval_primary(const char* s, int* pos, bool* ok) { return eval_range_func(fname, s, pos, ok); } + // No-arg: PI() + if (s[*pos] == '(' && strcmp(fname, "PI") == 0) { + (*pos)++; + skip_spaces(s, pos); + if (s[*pos] == ')') (*pos)++; + return 3.14159265358979; + } + + // Single-arg functions + if (s[*pos] == '(' && (strcmp(fname, "ABS") == 0 || + strcmp(fname, "SQRT") == 0 || + strcmp(fname, "INT") == 0 || + strcmp(fname, "FLOOR") == 0 || + strcmp(fname, "CEIL") == 0)) { + (*pos)++; + double arg = eval_expr(s, pos, ok); + skip_spaces(s, pos); + if (s[*pos] == ')') (*pos)++; + if (!*ok) return 0; + if (strcmp(fname, "ABS") == 0) return stb_fabs(arg); + if (strcmp(fname, "SQRT") == 0) return stb_sqrt(arg); + if (strcmp(fname, "INT") == 0) return (double)(long long)arg; + if (strcmp(fname, "FLOOR") == 0) return stb_floor(arg); + if (strcmp(fname, "CEIL") == 0) return stb_ceil(arg); + return 0; + } + + // Two-arg functions: ROUND, POW, MOD + if (s[*pos] == '(' && (strcmp(fname, "ROUND") == 0 || + strcmp(fname, "POW") == 0 || + strcmp(fname, "MOD") == 0)) { + (*pos)++; + double a = eval_expr(s, pos, ok); + skip_spaces(s, pos); + if (s[*pos] != ',') { *ok = false; return 0; } + (*pos)++; + double b = eval_expr(s, pos, ok); + skip_spaces(s, pos); + if (s[*pos] == ')') (*pos)++; + if (!*ok) return 0; + if (strcmp(fname, "POW") == 0) return stb_pow(a, b); + if (strcmp(fname, "MOD") == 0) { + if (b == 0) { *ok = false; return 0; } + return stb_fmod(a, b); + } + if (strcmp(fname, "ROUND") == 0) { + double factor = stb_pow(10.0, b); + return stb_floor(a * factor + 0.5) / factor; + } + return 0; + } + + // IF(condition, true_value, false_value) + if (s[*pos] == '(' && strcmp(fname, "IF") == 0) { + (*pos)++; + double cond = eval_expr(s, pos, ok); + skip_spaces(s, pos); + if (s[*pos] != ',') { *ok = false; return 0; } + (*pos)++; + double tv = eval_expr(s, pos, ok); + skip_spaces(s, pos); + if (s[*pos] != ',') { *ok = false; return 0; } + (*pos)++; + double fv = eval_expr(s, pos, ok); + skip_spaces(s, pos); + if (s[*pos] == ')') (*pos)++; + if (!*ok) return 0; + return (cond != 0.0) ? tv : fv; + } + + // Fall back to cell reference *pos = save_pos; int col, row, consumed; if (parse_cell_ref(s + *pos, &col, &row, &consumed)) { @@ -306,3 +406,142 @@ void cell_name(char* buf, int col, int row) { else if (r >= 10) { buf[1] = '0' + r / 10; buf[2] = '0' + r % 10; buf[3] = '\0'; } else { buf[1] = '0' + r; buf[2] = '\0'; } } + +// ============================================================================ +// Formula autocomplete +// ============================================================================ + +void update_autocomplete() { + g_ac_open = false; + g_ac_count = 0; + + if (!g_editing || g_edit_buf[0] != '=') return; + + // Find start of current alphabetic word at cursor + int word_start = g_edit_cursor; + while (word_start > 0 && is_alpha(g_edit_buf[word_start - 1])) + word_start--; + + int word_len = g_edit_cursor - word_start; + if (word_len == 0 || word_len > 7) return; + + // Don't autocomplete if cursor is right before more alpha chars (mid-word) + if (g_edit_cursor < g_edit_len && is_alpha(g_edit_buf[g_edit_cursor])) return; + + // Don't show if next char is '(' -- user already completed the name + if (g_edit_cursor < g_edit_len && g_edit_buf[g_edit_cursor] == '(') return; + + char partial[8]; + for (int i = 0; i < word_len; i++) + partial[i] = to_upper(g_edit_buf[word_start + i]); + partial[word_len] = '\0'; + + for (int i = 0; i < FORMULA_COUNT && g_ac_count < AC_MAX_MATCHES; i++) { + const char* name = g_formula_list[i].name; + bool match = true; + for (int j = 0; j < word_len; j++) { + if (name[j] == '\0' || to_upper(name[j]) != partial[j]) { + match = false; + break; + } + } + // Don't show exact matches (already fully typed) + if (match && name[word_len] != '\0') { + str_cpy(g_ac_matches[g_ac_count], name, 16); + str_cpy(g_ac_hints[g_ac_count], g_formula_list[i].hint, 32); + g_ac_count++; + } + } + + if (g_ac_count > 0) { + g_ac_open = true; + g_ac_sel = 0; + } +} + +void accept_autocomplete() { + if (!g_ac_open || g_ac_sel < 0 || g_ac_sel >= g_ac_count) return; + + // Find word start + int word_start = g_edit_cursor; + while (word_start > 0 && is_alpha(g_edit_buf[word_start - 1])) + word_start--; + + const char* name = g_ac_matches[g_ac_sel]; + int name_len = str_len(name); + + int old_len = g_edit_cursor - word_start; + int new_len = name_len + 1; // +1 for '(' + int delta = new_len - old_len; + + // Check buffer space + if (g_edit_len + delta >= CELL_TEXT_MAX - 1) { g_ac_open = false; return; } + + // Shift rest of buffer + if (delta > 0) { + for (int i = g_edit_len; i >= g_edit_cursor; i--) + g_edit_buf[i + delta] = g_edit_buf[i]; + } else if (delta < 0) { + for (int i = g_edit_cursor; i <= g_edit_len; i++) + g_edit_buf[i + delta] = g_edit_buf[i]; + } + + // Write function name + opening paren + for (int i = 0; i < name_len; i++) + g_edit_buf[word_start + i] = name[i]; + g_edit_buf[word_start + name_len] = '('; + + g_edit_len += delta; + g_edit_cursor = word_start + new_len; + g_edit_buf[g_edit_len] = '\0'; + + g_ac_open = false; +} + +// ============================================================================ +// Formula reference adjustment (for fill handle) +// ============================================================================ + +void adjust_formula_refs(const char* src, char* dst, int max, int dcol, int drow) { + int si = 0, di = 0; + while (src[si] && di < max - 1) { + if (is_alpha(src[si])) { + // Try to parse a cell reference + int col, row, consumed; + if (parse_cell_ref(src + si, &col, &row, &consumed)) { + // Check this is actually a cell ref and not part of a function name + // by looking backward: if the previous char is also alpha, it's a + // function name, not a cell ref + bool is_func_part = (si > 0 && is_alpha(src[si - 1])); + if (is_func_part) { + dst[di++] = src[si++]; + continue; + } + int nc = col + dcol; + int nr = row + drow; + if (nc < 0) nc = 0; + if (nc >= MAX_COLS) nc = MAX_COLS - 1; + if (nr < 0) nr = 0; + if (nr >= MAX_ROWS) nr = MAX_ROWS - 1; + dst[di++] = 'A' + nc; + int rv = nr + 1; + if (rv >= 100 && di < max - 3) { + dst[di++] = '0' + rv / 100; + dst[di++] = '0' + (rv / 10) % 10; + dst[di++] = '0' + rv % 10; + } else if (rv >= 10 && di < max - 2) { + dst[di++] = '0' + rv / 10; + dst[di++] = '0' + rv % 10; + } else { + dst[di++] = '0' + rv; + } + si += consumed; + } else { + dst[di++] = src[si++]; + } + } else { + dst[di++] = src[si++]; + } + } + dst[di] = '\0'; +} diff --git a/programs/src/spreadsheet/main.cpp b/programs/src/spreadsheet/main.cpp index 9267415..80ea820 100644 --- a/programs/src/spreadsheet/main.cpp +++ b/programs/src/spreadsheet/main.cpp @@ -60,6 +60,25 @@ UndoEntry* g_undo[UNDO_MAX + 1]; int g_undo_count = 0; int g_undo_pos = 0; +// Formula autocomplete +bool g_ac_open = false; +int g_ac_sel = 0; +int g_ac_count = 0; +char g_ac_matches[AC_MAX_MATCHES][16]; +char g_ac_hints[AC_MAX_MATCHES][32]; + +// Fill handle +bool g_fill_dragging = false; +int g_fill_target_row = 0; + +// Mouse drag selection +bool g_mouse_selecting = false; + +// Double-click detection +uint64_t g_last_click_ms = 0; +int g_last_click_col = -1; +int g_last_click_row = -1; + // ============================================================================ // Hit testing // ============================================================================ @@ -89,6 +108,28 @@ bool hit_cell(int mx, int my, int* out_col, int* out_row) { return true; } +bool hit_fill_handle(int mx, int my) { + if (g_editing) return false; + + int c0, r0, c1, r1; + sel_range(&c0, &r0, &c1, &r1); + + int pbh = g_pathbar_open ? PATHBAR_H : 0; + int grid_y = TOOLBAR_H + pbh + FORMULA_BAR_H + COL_HEADER_H; + + int sx = col_x(c0) - g_scroll_x; + int sw = 0; + for (int c = c0; c <= c1; c++) sw += g_col_widths[c]; + int sy = grid_y + r0 * ROW_H - g_scroll_y; + int sh = (r1 - r0 + 1) * ROW_H; + + int fhx = sx + sw - FILL_HANDLE_SIZE / 2; + int fhy = sy + sh - FILL_HANDLE_SIZE / 2; + + return mx >= fhx - 3 && mx <= fhx + FILL_HANDLE_SIZE + 3 && + my >= fhy - 3 && my <= fhy + FILL_HANDLE_SIZE + 3; +} + bool handle_toolbar_click(int mx, int my) { if (my >= TOOLBAR_H || my < TB_BTN_Y || my >= TB_BTN_Y + TB_BTN_SIZE) return false; @@ -202,8 +243,7 @@ extern "C" void _start() { char args[512] = {}; int arglen = montauk::getargs(args, sizeof(args)); if (arglen > 0 && args[0]) { - str_cpy(g_filepath, args, 256); - load_file(g_filepath); + load_file(args); } // Build window title @@ -295,21 +335,56 @@ extern "C" void _start() { goto done_keys; } + // Autocomplete interaction (when editing with autocomplete open) + if (g_ac_open && g_editing) { + if (key.scancode == 0x48) { // Up + g_ac_sel = (g_ac_sel - 1 + g_ac_count) % g_ac_count; + redraw = true; + goto done_keys; + } + if (key.scancode == 0x50) { // Down + g_ac_sel = (g_ac_sel + 1) % g_ac_count; + redraw = true; + goto done_keys; + } + if (key.ascii == '\t') { // Tab: accept autocomplete + accept_autocomplete(); + update_autocomplete(); + redraw = true; + goto done_keys; + } + if (key.ascii == '\n' || key.ascii == '\r') { + // Enter: accept autocomplete then commit + accept_autocomplete(); + g_ac_open = false; + commit_edit(); + if (g_sel_row < MAX_ROWS - 1) g_sel_row++; + ensure_sel_visible(); + redraw = true; + goto done_keys; + } + if (key.scancode == 0x01) { // Escape: close autocomplete only + g_ac_open = false; + redraw = true; + goto done_keys; + } + } + // Escape: cancel edit or quit if (key.scancode == 0x01) { - if (g_editing) { cancel_edit(); redraw = true; } + if (g_editing) { cancel_edit(); g_ac_open = false; redraw = true; } else break; } // Enter: commit edit and move down else if (key.ascii == '\n' || key.ascii == '\r') { - if (g_editing) commit_edit(); + if (g_editing) { commit_edit(); g_ac_open = false; } if (g_sel_row < MAX_ROWS - 1) g_sel_row++; ensure_sel_visible(); redraw = true; } - // Tab: commit and move right + // Tab: commit and move right (or accept autocomplete above) else if (key.ascii == '\t') { - if (g_editing) commit_edit(); + if (g_editing) { commit_edit(); g_ac_open = false; } if (key.shift) { if (g_sel_col > 0) g_sel_col--; } else { @@ -372,6 +447,7 @@ extern "C" void _start() { g_edit_len--; g_edit_cursor--; g_edit_buf[g_edit_len] = '\0'; + update_autocomplete(); } redraw = true; } else { @@ -394,6 +470,7 @@ extern "C" void _start() { g_edit_buf[i] = g_edit_buf[i + 1]; g_edit_len--; g_edit_buf[g_edit_len] = '\0'; + update_autocomplete(); } redraw = true; } else { @@ -411,10 +488,40 @@ extern "C" void _start() { // Edit mode arrow keys (cursor movement within formula bar) else if (key.scancode == 0x4B && g_editing) { if (g_edit_cursor > 0) g_edit_cursor--; + update_autocomplete(); redraw = true; } else if (key.scancode == 0x4D && g_editing) { if (g_edit_cursor < g_edit_len) g_edit_cursor++; + update_autocomplete(); + redraw = true; + } + // Home key + else if (key.scancode == 0x47) { + if (g_editing) { + g_edit_cursor = 0; + update_autocomplete(); + } else { + g_sel_col = 0; + clear_selection(); + ensure_sel_visible(); + } + redraw = true; + } + // End key + else if (key.scancode == 0x4F) { + if (g_editing) { + g_edit_cursor = g_edit_len; + update_autocomplete(); + } else { + // Jump to last non-empty column in current row + int last = 0; + for (int c = 0; c < MAX_COLS; c++) + if (g_cells[g_sel_row][c].input[0]) last = c; + g_sel_col = last; + clear_selection(); + ensure_sel_visible(); + } redraw = true; } // Ctrl+B: bold toggle @@ -487,6 +594,7 @@ extern "C" void _start() { g_edit_cursor++; g_edit_buf[g_edit_len] = '\0'; } + update_autocomplete(); redraw = true; } // F2: edit current cell content (append mode) @@ -510,11 +618,15 @@ extern "C" void _start() { int pbh = g_pathbar_open ? PATHBAR_H : 0; int header_y = TOOLBAR_H + pbh + FORMULA_BAR_H; - // Update cursor style: resize_h when hovering near column border in header + // Update cursor style { int cursor = 0; // arrow if (g_col_resizing) { cursor = 1; // resize_h while dragging + } else if (g_fill_dragging) { + cursor = 2; // crosshair during fill + } else if (hit_fill_handle(mx, my)) { + cursor = 2; // crosshair on fill handle } else if (my >= header_y && my < header_y + COL_HEADER_H) { for (int c = 0; c < MAX_COLS; c++) { int cx = col_x(c) - g_scroll_x + g_col_widths[c] - 1; @@ -527,6 +639,33 @@ extern "C" void _start() { montauk::win_setcursor(win_id, cursor); } + // Fill handle: drag in progress + if (g_fill_dragging) { + if (left_held) { + int col, row; + if (hit_cell(mx, my, &col, &row)) { + int c0, r0, c1, r1; + sel_range(&c0, &r0, &c1, &r1); + if (row > r1 && row != g_fill_target_row) { + g_fill_target_row = row; + redraw = true; + } + } + } + if (left_released) { + int c0, r0, c1, r1; + sel_range(&c0, &r0, &c1, &r1); + if (g_fill_target_row > r1) { + fill_down(r0, c0, r1, c1, g_fill_target_row); + g_sel_row = g_fill_target_row; + g_has_selection = true; + } + g_fill_dragging = false; + redraw = true; + } + goto done_mouse; + } + // Column resize: drag in progress if (g_col_resizing) { if (left_held) { @@ -543,11 +682,39 @@ extern "C" void _start() { goto done_mouse; } - // Column resize: start drag (click near right edge of column header) + // Mouse drag selection: extend while dragging + if (g_mouse_selecting && left_held && !clicked) { + int col, row; + if (hit_cell(mx, my, &col, &row)) { + if (col != g_sel_col || row != g_sel_row) { + g_sel_col = col; + g_sel_row = row; + g_has_selection = (col != g_anchor_col || row != g_anchor_row); + redraw = true; + } + } + } + if (left_released) { + g_mouse_selecting = false; + } + + // Column resize or auto-fit: click/double-click near column header border if (clicked && my >= header_y && my < header_y + COL_HEADER_H) { for (int c = 0; c < MAX_COLS; c++) { int cx = col_x(c) - g_scroll_x + g_col_widths[c] - 1; if (mx >= cx - COL_RESIZE_GRAB && mx <= cx + COL_RESIZE_GRAB) { + // Double-click: auto-fit column width + uint64_t now = montauk::get_milliseconds(); + if (g_last_click_col == c && (now - g_last_click_ms) < DBLCLICK_MS) { + auto_fit_column(c); + clamp_scroll(); + g_last_click_ms = 0; + redraw = true; + goto done_mouse; + } + g_last_click_ms = now; + g_last_click_col = c; + g_col_resizing = true; g_col_resize_idx = c; g_col_resize_start_x = mx; @@ -565,12 +732,41 @@ extern "C" void _start() { redraw = true; } else { + // Check fill handle first + if (hit_fill_handle(mx, my)) { + int c0, r0, c1, r1; + sel_range(&c0, &r0, &c1, &r1); + g_fill_dragging = true; + g_fill_target_row = r1; + goto done_mouse; + } + int col, row; if (hit_cell(mx, my, &col, &row)) { - if (g_editing) commit_edit(); + if (g_editing) { commit_edit(); g_ac_open = false; } + + // Double-click cell: start editing + uint64_t now = montauk::get_milliseconds(); + if (col == g_last_click_col && row == g_last_click_row && + (now - g_last_click_ms) < DBLCLICK_MS) { + g_sel_col = col; + g_sel_row = row; + clear_selection(); + start_editing(); + g_last_click_ms = 0; + redraw = true; + goto done_mouse; + } + g_last_click_ms = now; + g_last_click_col = col; + g_last_click_row = row; + g_sel_col = col; g_sel_row = row; - clear_selection(); + g_anchor_col = col; + g_anchor_row = row; + g_has_selection = false; + g_mouse_selecting = true; g_fmt_dropdown_open = false; redraw = true; } diff --git a/programs/src/spreadsheet/render.cpp b/programs/src/spreadsheet/render.cpp index a6648c0..cac01dd 100644 --- a/programs/src/spreadsheet/render.cpp +++ b/programs/src/spreadsheet/render.cpp @@ -270,7 +270,7 @@ void render(uint32_t* pixels) { px_hline(pixels, g_win_w, g_win_h, ROW_HEADER_W, y + ROW_H - 1, g_win_w - ROW_HEADER_W, GRID_COLOR); } - // ---- Selection border ---- + // ---- Selection border + fill handle ---- { int c0, r0, c1, r1; sel_range(&c0, &r0, &c1, &r1); @@ -281,8 +281,27 @@ void render(uint32_t* pixels) { for (int c = c0; c <= c1; c++) sw += g_col_widths[c]; int sh = (r1 - r0 + 1) * ROW_H; + // Fill drag preview + if (g_fill_dragging && g_fill_target_row > r1) { + int fill_sh = (g_fill_target_row - r0 + 1) * ROW_H; + // Dashed border for fill preview area + for (int dx = 0; dx < sw; dx += 6) { + int seg = dx + 3 < sw ? 3 : sw - dx; + px_hline(pixels, g_win_w, g_win_h, sx + dx, sy_sel + fill_sh - 1, seg, SELECT_BORDER); + } + px_vline(pixels, g_win_w, g_win_h, sx, sy_sel + sh, fill_sh - sh, SELECT_BORDER); + px_vline(pixels, g_win_w, g_win_h, sx + sw - 1, sy_sel + sh, fill_sh - sh, SELECT_BORDER); + } + px_rect(pixels, g_win_w, g_win_h, sx, sy_sel, sw, sh, SELECT_BORDER); px_rect(pixels, g_win_w, g_win_h, sx + 1, sy_sel + 1, sw - 2, sh - 2, SELECT_BORDER); + + // Fill handle (small blue square at bottom-right corner) + if (!g_editing) { + int fhx = sx + sw - FILL_HANDLE_SIZE / 2; + int fhy = sy_sel + sh - FILL_HANDLE_SIZE / 2; + px_fill(pixels, g_win_w, g_win_h, fhx, fhy, FILL_HANDLE_SIZE, FILL_HANDLE_SIZE, SELECT_BORDER); + } } // ---- Status bar ---- @@ -302,15 +321,35 @@ void render(uint32_t* pixels) { int sty = sy + (STATUS_BAR_H - HEADER_FONT) / 2; g_font->draw_to_buffer(pixels, g_win_w, g_win_h, 6, sty, status, STATUS_TEXT, HEADER_FONT); - char right[64]; + char right[128]; if (g_has_selection) { int c0, r0, c1, r1; sel_range(&c0, &r0, &c1, &r1); - char n0[8], n1[8]; - cell_name(n0, c0, r0); - cell_name(n1, c1, r1); - int ncells = (c1 - c0 + 1) * (r1 - r0 + 1); - snprintf(right, 64, "%s:%s (%d cells) ", n0, n1, ncells); + + // Calculate aggregates for numeric cells + double sum = 0; + int num_count = 0; + for (int r = r0; r <= r1; r++) { + for (int c = c0; c <= c1; c++) { + if (g_cells[r][c].type == CT_NUMBER || g_cells[r][c].type == CT_FORMULA) { + sum += g_cells[r][c].value; + num_count++; + } + } + } + + if (num_count > 0) { + char sbuf[24], abuf[24]; + double_to_str(sbuf, 24, sum); + double_to_str(abuf, 24, sum / num_count); + snprintf(right, 128, "SUM=%s AVG=%s COUNT=%d ", sbuf, abuf, num_count); + } else { + char n0[8], n1[8]; + cell_name(n0, c0, r0); + cell_name(n1, c1, r1); + int ncells = (c1 - c0 + 1) * (r1 - r0 + 1); + snprintf(right, 128, "%s:%s (%d cells) ", n0, n1, ncells); + } } else { Cell* sel = &g_cells[g_sel_row][g_sel_col]; char cname[8]; @@ -318,9 +357,9 @@ void render(uint32_t* pixels) { if (sel->type == CT_FORMULA || sel->type == CT_NUMBER) { char vbuf[32]; double_to_str(vbuf, 32, sel->value); - snprintf(right, 64, "%s = %s ", cname, vbuf); + snprintf(right, 128, "%s = %s ", cname, vbuf); } else { - snprintf(right, 64, "%s ", cname); + snprintf(right, 128, "%s ", cname); } } int rw = g_font->measure_text(right, HEADER_FONT); @@ -348,4 +387,48 @@ void render(uint32_t* pixels) { dx + 8, iy + (item_h - HEADER_FONT) / 2, items[i], CELL_TEXT, HEADER_FONT); } } + + // ---- Autocomplete dropdown overlay ---- + if (g_ac_open && g_editing && g_font) { + int fbar_y_ac = TOOLBAR_H + pathbar_h; + int fx = sep_x + 10; + + // Measure text up to the start of the current word + int ws = g_edit_cursor; + while (ws > 0 && is_alpha(g_edit_buf[ws - 1])) ws--; + char word_prefix[CELL_TEXT_MAX]; + int wpi = 0; + for (int i = 0; i < ws && wpi < CELL_TEXT_MAX - 1; i++) + word_prefix[wpi++] = g_edit_buf[i]; + word_prefix[wpi] = '\0'; + + int ac_x = fx + g_font->measure_text(word_prefix, FONT_SIZE); + int ac_y = fbar_y_ac + FORMULA_BAR_H; + int ac_item_h = 24; + int ac_w = 160; + int ac_h = g_ac_count * ac_item_h + 4; + + // Shadow + px_fill(pixels, g_win_w, g_win_h, ac_x + 2, ac_y + 2, ac_w, ac_h, + Color::from_rgb(0xAA, 0xAA, 0xAA)); + // Background + px_fill(pixels, g_win_w, g_win_h, ac_x, ac_y, ac_w, ac_h, BG_COLOR); + px_rect(pixels, g_win_w, g_win_h, ac_x, ac_y, ac_w, ac_h, GRID_COLOR); + + for (int i = 0; i < g_ac_count; i++) { + int iy = ac_y + 2 + i * ac_item_h; + if (i == g_ac_sel) + px_fill(pixels, g_win_w, g_win_h, ac_x + 2, iy, ac_w - 4, ac_item_h - 2, SELECT_FILL); + + TrueTypeFont* bf = g_font_bold ? g_font_bold : g_font; + bf->draw_to_buffer(pixels, g_win_w, g_win_h, + ac_x + 6, iy + (ac_item_h - HEADER_FONT) / 2, + g_ac_matches[i], CELL_TEXT, HEADER_FONT); + + int nw = bf->measure_text(g_ac_matches[i], HEADER_FONT); + g_font->draw_to_buffer(pixels, g_win_w, g_win_h, + ac_x + 12 + nw, iy + (ac_item_h - HEADER_FONT) / 2, + g_ac_hints[i], HEADER_TEXT, HEADER_FONT); + } + } } diff --git a/programs/src/spreadsheet/spreadsheet.h b/programs/src/spreadsheet/spreadsheet.h index 51a5777..27502c5 100644 --- a/programs/src/spreadsheet/spreadsheet.h +++ b/programs/src/spreadsheet/spreadsheet.h @@ -11,6 +11,7 @@ #include #include #include +#include extern "C" { #include @@ -41,6 +42,9 @@ static constexpr int DEF_COL_W = 100; static constexpr int MIN_COL_W = 30; static constexpr int ROW_H = 26; static constexpr int COL_RESIZE_GRAB = 5; // pixels from border edge for grab zone +static constexpr int FILL_HANDLE_SIZE = 6; +static constexpr int AC_MAX_MATCHES = 8; +static constexpr int DBLCLICK_MS = 400; static constexpr int CELL_TEXT_MAX = 128; static constexpr int FONT_SIZE = 18; @@ -174,6 +178,25 @@ extern UndoEntry* g_undo[UNDO_MAX + 1]; extern int g_undo_count; extern int g_undo_pos; +// Formula autocomplete +extern bool g_ac_open; +extern int g_ac_sel; +extern int g_ac_count; +extern char g_ac_matches[AC_MAX_MATCHES][16]; +extern char g_ac_hints[AC_MAX_MATCHES][32]; + +// Fill handle +extern bool g_fill_dragging; +extern int g_fill_target_row; + +// Mouse drag selection +extern bool g_mouse_selecting; + +// Double-click detection +extern uint64_t g_last_click_ms; +extern int g_last_click_col; +extern int g_last_click_row; + // ============================================================================ // Function declarations — helpers.cpp // ============================================================================ @@ -203,6 +226,9 @@ int content_width(); int content_height(); void cell_name(char* buf, int col, int row); void format_value(char* buf, int max, double val, NumFormat fmt); +void update_autocomplete(); +void accept_autocomplete(); +void adjust_formula_refs(const char* src, char* dst, int max, int dcol, int drow); // ============================================================================ // Function declarations — fileio.cpp @@ -231,6 +257,8 @@ void apply_align(CellAlign a); void apply_format(NumFormat f); void clamp_scroll(); void ensure_sel_visible(); +void fill_down(int src_r0, int src_c0, int src_r1, int src_c1, int dst_r1); +void auto_fit_column(int col); // ============================================================================ // Function declarations — render.cpp @@ -243,5 +271,6 @@ void render(uint32_t* pixels); // ============================================================================ bool hit_cell(int mx, int my, int* out_col, int* out_row); +bool hit_fill_handle(int mx, int my); bool handle_toolbar_click(int mx, int my); bool handle_fmt_dropdown_click(int mx, int my); diff --git a/programs/src/tcc/COPYING b/programs/src/tcc/COPYING new file mode 100644 index 0000000..223ede7 --- /dev/null +++ b/programs/src/tcc/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This 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 of the License, or (at your option) any later version. + + This 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 this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/programs/src/tcc/Makefile b/programs/src/tcc/Makefile new file mode 100644 index 0000000..3ff4a79 --- /dev/null +++ b/programs/src/tcc/Makefile @@ -0,0 +1,153 @@ +# Makefile for TCC on MontaukOS +# Copyright (c) 2026 Daniel Hammer + +MAKEFLAGS += -rR +.SUFFIXES: + +# ---- Toolchain ---- + +TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-elf- +ifneq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),) + CC := $(TOOLCHAIN_PREFIX)gcc + CXX := $(TOOLCHAIN_PREFIX)g++ + AR := $(TOOLCHAIN_PREFIX)ar +else + CC := gcc + CXX := g++ + AR := ar +endif + +# ---- Paths ---- + +PROG_INC := ../../include +LIBDIR := ../../lib +OBJDIR := obj +BINDIR := ../../bin/os + +# ---- Compiler flags ---- + +CFLAGS := \ + -std=gnu11 \ + -g -O2 -pipe \ + -Wall \ + -Wno-unused-parameter \ + -Wno-unused-function \ + -Wno-sign-compare \ + -Wno-misleading-indentation \ + -Wno-implicit-fallthrough \ + -Wno-stringop-truncation \ + -Wno-format-truncation \ + -nostdinc \ + -ffreestanding \ + -fno-stack-protector \ + -fno-stack-check \ + -fno-PIC \ + -ffunction-sections \ + -fdata-sections \ + -m64 \ + -march=x86-64 \ + -msse \ + -msse2 \ + -mno-red-zone \ + -mcmodel=small \ + -fno-tree-loop-distribute-patterns \ + -D__MONTAUKOS__=1 \ + -DONE_SOURCE=0 \ + -DTCC_TARGET_X86_64=1 \ + -DCONFIG_TCC_STATIC=1 \ + -I. \ + -isystem $(PROG_INC)/libc \ + -isystem $(shell $(CC) -print-file-name=include) + +LDFLAGS := \ + -nostdlib \ + -static \ + -Wl,--build-id=none \ + -Wl,--gc-sections \ + -Wl,-m,elf_x86_64 \ + -z max-page-size=0x1000 \ + -T ../../link.ld + +# ---- Sources ---- + +TCC_SRCS := \ + libtcc.c \ + tccpp.c \ + tccgen.c \ + tccelf.c \ + tccasm.c \ + tccdbg.c \ + x86_64-gen.c \ + x86_64-link.c \ + i386-asm.c \ + tcc.c + +COMPAT_SRCS := \ + montauk_main.c + +ASM_SRCS := \ + setjmp.S + +TCC_OBJS := $(patsubst %.c,$(OBJDIR)/%.o,$(TCC_SRCS)) +COMPAT_OBJS := $(patsubst %.c,$(OBJDIR)/%.o,$(COMPAT_SRCS)) +ASM_OBJS := $(patsubst %.S,$(OBJDIR)/%.o,$(ASM_SRCS)) + +ALL_OBJS := $(TCC_OBJS) $(COMPAT_OBJS) $(ASM_OBJS) + +TARGET := $(BINDIR)/tcc.elf + +# ---- CRT objects (compiled for linking by TCC) ---- + +CRT_CFLAGS := \ + -std=gnu11 \ + -O2 \ + -nostdinc \ + -ffreestanding \ + -fno-stack-protector \ + -fno-PIC \ + -m64 \ + -march=x86-64 \ + -mno-red-zone \ + -fno-tree-loop-distribute-patterns \ + -isystem $(PROG_INC)/libc \ + -isystem $(shell $(CC) -print-file-name=include) + +CRT_DIR := ../../bin/lib/tcc/lib +CRT_OBJS := $(CRT_DIR)/crt1.o $(CRT_DIR)/crti.o $(CRT_DIR)/crtn.o + +# ---- Rules ---- + +.PHONY: all clean + +all: $(TARGET) $(CRT_OBJS) $(CRT_DIR)/libc.a + +$(TARGET): $(ALL_OBJS) $(LIBDIR)/libc/liblibc.a + @mkdir -p $(BINDIR) + $(CC) $(CFLAGS) $(LDFLAGS) $(ALL_OBJS) $(LIBDIR)/libc/liblibc.a -lgcc -o $@ + +$(OBJDIR)/%.o: %.c Makefile config.h montauk_compat.h + @mkdir -p $(OBJDIR) + $(CC) $(CFLAGS) -c $< -o $@ + +$(OBJDIR)/%.o: %.S Makefile + @mkdir -p $(OBJDIR) + $(CC) $(CFLAGS) -c $< -o $@ + +$(CRT_DIR)/crt1.o: crt/crt1.c + @mkdir -p $(CRT_DIR) + $(CC) $(CRT_CFLAGS) -c $< -o $@ + +$(CRT_DIR)/crti.o: crt/crti.c + @mkdir -p $(CRT_DIR) + $(CC) $(CRT_CFLAGS) -c $< -o $@ + +$(CRT_DIR)/crtn.o: crt/crtn.c + @mkdir -p $(CRT_DIR) + $(CC) $(CRT_CFLAGS) -c $< -o $@ + +$(CRT_DIR)/libc.a: $(LIBDIR)/libc/liblibc.a + @mkdir -p $(CRT_DIR) + cp $< $@ + +clean: + rm -rf $(OBJDIR) $(TARGET) diff --git a/programs/src/tcc/VERSION b/programs/src/tcc/VERSION new file mode 100644 index 0000000..7cdd3b4 --- /dev/null +++ b/programs/src/tcc/VERSION @@ -0,0 +1 @@ +0.9.28rc \ No newline at end of file diff --git a/programs/src/tcc/coff.h b/programs/src/tcc/coff.h new file mode 100644 index 0000000..e8e6185 --- /dev/null +++ b/programs/src/tcc/coff.h @@ -0,0 +1,446 @@ +/**************************************************************************/ +/* COFF.H */ +/* COFF data structures and related definitions used by the linker */ +/**************************************************************************/ + +/*------------------------------------------------------------------------*/ +/* COFF FILE HEADER */ +/*------------------------------------------------------------------------*/ +struct filehdr { + unsigned short f_magic; /* magic number */ + unsigned short f_nscns; /* number of sections */ + long f_timdat; /* time & date stamp */ + long f_symptr; /* file pointer to symtab */ + long f_nsyms; /* number of symtab entries */ + unsigned short f_opthdr; /* sizeof(optional hdr) */ + unsigned short f_flags; /* flags */ + unsigned short f_TargetID; /* for C6x = 0x0099 */ + }; + +/*------------------------------------------------------------------------*/ +/* File header flags */ +/*------------------------------------------------------------------------*/ +#define F_RELFLG 0x01 /* relocation info stripped from file */ +#define F_EXEC 0x02 /* file is executable (no unresolved refs) */ +#define F_LNNO 0x04 /* line numbers stripped from file */ +#define F_LSYMS 0x08 /* local symbols stripped from file */ +#define F_GSP10 0x10 /* 34010 version */ +#define F_GSP20 0x20 /* 34020 version */ +#define F_SWABD 0x40 /* bytes swabbed (in names) */ +#define F_AR16WR 0x80 /* byte ordering of an AR16WR (PDP-11) */ +#define F_LITTLE 0x100 /* byte ordering of an AR32WR (vax) */ +#define F_BIG 0x200 /* byte ordering of an AR32W (3B, maxi) */ +#define F_PATCH 0x400 /* contains "patch" list in optional header */ +#define F_NODF 0x400 + +#define F_VERSION (F_GSP10 | F_GSP20) +#define F_BYTE_ORDER (F_LITTLE | F_BIG) +#define FILHDR struct filehdr + +/* #define FILHSZ sizeof(FILHDR) */ +#define FILHSZ 22 /* above rounds to align on 4 bytes which causes problems */ + +#define COFF_C67_MAGIC 0x00c2 + +/*------------------------------------------------------------------------*/ +/* Macros to recognize magic numbers */ +/*------------------------------------------------------------------------*/ +#define ISMAGIC(x) (((unsigned short)(x))==(unsigned short)magic) +#define ISARCHIVE(x) ((((unsigned short)(x))==(unsigned short)ARTYPE)) +#define BADMAGIC(x) (((unsigned short)(x) & 0x8080) && !ISMAGIC(x)) + + +/*------------------------------------------------------------------------*/ +/* OPTIONAL FILE HEADER */ +/*------------------------------------------------------------------------*/ +typedef struct aouthdr { + short magic; /* see magic.h */ + short vstamp; /* version stamp */ + long tsize; /* text size in bytes, padded to FW bdry*/ + long dsize; /* initialized data " " */ + long bsize; /* uninitialized data " " */ + long entrypt; /* entry pt. */ + long text_start; /* base of text used for this file */ + long data_start; /* base of data used for this file */ +} AOUTHDR; + +#define AOUTSZ sizeof(AOUTHDR) + +/*----------------------------------------------------------------------*/ +/* When a UNIX aout header is to be built in the optional header, */ +/* the following magic numbers can appear in that header: */ +/* */ +/* AOUT1MAGIC : default : readonly sharable text segment */ +/* AOUT2MAGIC: : writable text segment */ +/* PAGEMAGIC : : configured for paging */ +/*----------------------------------------------------------------------*/ +#define AOUT1MAGIC 0410 +#define AOUT2MAGIC 0407 +#define PAGEMAGIC 0413 + + +/*------------------------------------------------------------------------*/ +/* COMMON ARCHIVE FILE STRUCTURES */ +/* */ +/* ARCHIVE File Organization: */ +/* _______________________________________________ */ +/* |__________ARCHIVE_MAGIC_STRING_______________| */ +/* |__________ARCHIVE_FILE_MEMBER_1______________| */ +/* | | */ +/* | Archive File Header "ar_hdr" | */ +/* |.............................................| */ +/* | Member Contents | */ +/* | 1. External symbol directory | */ +/* | 2. Text file | */ +/* |_____________________________________________| */ +/* |________ARCHIVE_FILE_MEMBER_2________________| */ +/* | "ar_hdr" | */ +/* |.............................................| */ +/* | Member Contents (.o or text file) | */ +/* |_____________________________________________| */ +/* | . . . | */ +/* | . . . | */ +/* | . . . | */ +/* |_____________________________________________| */ +/* |________ARCHIVE_FILE_MEMBER_n________________| */ +/* | "ar_hdr" | */ +/* |.............................................| */ +/* | Member Contents | */ +/* |_____________________________________________| */ +/* */ +/*------------------------------------------------------------------------*/ + +#define COFF_ARMAG "!\n" +#define SARMAG 8 +#define ARFMAG "`\n" + +struct ar_hdr /* archive file member header - printable ascii */ +{ + char ar_name[16]; /* file member name - `/' terminated */ + char ar_date[12]; /* file member date - decimal */ + char ar_uid[6]; /* file member user id - decimal */ + char ar_gid[6]; /* file member group id - decimal */ + char ar_mode[8]; /* file member mode - octal */ + char ar_size[10]; /* file member size - decimal */ + char ar_fmag[2]; /* ARFMAG - string to end header */ +}; + + +/*------------------------------------------------------------------------*/ +/* SECTION HEADER */ +/*------------------------------------------------------------------------*/ +struct scnhdr { + char s_name[8]; /* section name */ + long s_paddr; /* physical address */ + long s_vaddr; /* virtual address */ + long s_size; /* section size */ + long s_scnptr; /* file ptr to raw data for section */ + long s_relptr; /* file ptr to relocation */ + long s_lnnoptr; /* file ptr to line numbers */ + unsigned int s_nreloc; /* number of relocation entries */ + unsigned int s_nlnno; /* number of line number entries */ + unsigned int s_flags; /* flags */ + unsigned short s_reserved; /* reserved byte */ + unsigned short s_page; /* memory page id */ + }; + +#define SCNHDR struct scnhdr +#define SCNHSZ sizeof(SCNHDR) + +/*------------------------------------------------------------------------*/ +/* Define constants for names of "special" sections */ +/*------------------------------------------------------------------------*/ +/* #define _TEXT ".text" */ +#define _DATA ".data" +#define _BSS ".bss" +#define _CINIT ".cinit" +#define _TV ".tv" + +/*------------------------------------------------------------------------*/ +/* The low 4 bits of s_flags is used as a section "type" */ +/*------------------------------------------------------------------------*/ +#define STYP_REG 0x00 /* "regular" : allocated, relocated, loaded */ +#define STYP_DSECT 0x01 /* "dummy" : not allocated, relocated, not loaded */ +#define STYP_NOLOAD 0x02 /* "noload" : allocated, relocated, not loaded */ +#define STYP_GROUP 0x04 /* "grouped" : formed of input sections */ +#define STYP_PAD 0x08 /* "padding" : not allocated, not relocated, loaded */ +#define STYP_COPY 0x10 /* "copy" : used for C init tables - + not allocated, relocated, + loaded; reloc & lineno + entries processed normally */ +#define STYP_TEXT 0x20 /* section contains text only */ +#define STYP_DATA 0x40 /* section contains data only */ +#define STYP_BSS 0x80 /* section contains bss only */ + +#define STYP_ALIGN 0x100 /* align flag passed by old version assemblers */ +#define ALIGN_MASK 0x0F00 /* part of s_flags that is used for align vals */ +#define ALIGNSIZE(x) (1 << ((x & ALIGN_MASK) >> 8)) + + +/*------------------------------------------------------------------------*/ +/* RELOCATION ENTRIES */ +/*------------------------------------------------------------------------*/ +struct reloc +{ + long r_vaddr; /* (virtual) address of reference */ + short r_symndx; /* index into symbol table */ + unsigned short r_disp; /* additional bits for address calculation */ + unsigned short r_type; /* relocation type */ +}; + +#define RELOC struct reloc +#define RELSZ 10 /* sizeof(RELOC) */ + +/*--------------------------------------------------------------------------*/ +/* define all relocation types */ +/*--------------------------------------------------------------------------*/ + +#define R_ABS 0 /* absolute address - no relocation */ +#define R_DIR16 01 /* UNUSED */ +#define R_REL16 02 /* UNUSED */ +#define R_DIR24 04 /* UNUSED */ +#define R_REL24 05 /* 24 bits, direct */ +#define R_DIR32 06 /* UNUSED */ +#define R_RELBYTE 017 /* 8 bits, direct */ +#define R_RELWORD 020 /* 16 bits, direct */ +#define R_RELLONG 021 /* 32 bits, direct */ +#define R_PCRBYTE 022 /* 8 bits, PC-relative */ +#define R_PCRWORD 023 /* 16 bits, PC-relative */ +#define R_PCRLONG 024 /* 32 bits, PC-relative */ +#define R_OCRLONG 030 /* GSP: 32 bits, one's complement direct */ +#define R_GSPPCR16 031 /* GSP: 16 bits, PC relative (in words) */ +#define R_GSPOPR32 032 /* GSP: 32 bits, direct big-endian */ +#define R_PARTLS16 040 /* Brahma: 16 bit offset of 24 bit address*/ +#define R_PARTMS8 041 /* Brahma: 8 bit page of 24 bit address */ +#define R_PARTLS7 050 /* DSP: 7 bit offset of 16 bit address */ +#define R_PARTMS9 051 /* DSP: 9 bit page of 16 bit address */ +#define R_REL13 052 /* DSP: 13 bits, direct */ + + +/*------------------------------------------------------------------------*/ +/* LINE NUMBER ENTRIES */ +/*------------------------------------------------------------------------*/ +struct lineno +{ + union + { + long l_symndx ; /* sym. table index of function name + iff l_lnno == 0 */ + long l_paddr ; /* (physical) address of line number */ + } l_addr ; + unsigned short l_lnno ; /* line number */ +}; + +#define LINENO struct lineno +#define LINESZ 6 /* sizeof(LINENO) */ + + +/*------------------------------------------------------------------------*/ +/* STORAGE CLASSES */ +/*------------------------------------------------------------------------*/ +#define C_EFCN -1 /* physical end of function */ +#define C_NULL 0 +#define C_AUTO 1 /* automatic variable */ +#define C_EXT 2 /* external symbol */ +#define C_STAT 3 /* static */ +#define C_REG 4 /* register variable */ +#define C_EXTDEF 5 /* external definition */ +#define C_LABEL 6 /* label */ +#define C_ULABEL 7 /* undefined label */ +#define C_MOS 8 /* member of structure */ +#define C_ARG 9 /* function argument */ +#define C_STRTAG 10 /* structure tag */ +#define C_MOU 11 /* member of union */ +#define C_UNTAG 12 /* union tag */ +#define C_TPDEF 13 /* type definition */ +#define C_USTATIC 14 /* undefined static */ +#define C_ENTAG 15 /* enumeration tag */ +#define C_MOE 16 /* member of enumeration */ +#define C_REGPARM 17 /* register parameter */ +#define C_FIELD 18 /* bit field */ + +#define C_BLOCK 100 /* ".bb" or ".eb" */ +#define C_FCN 101 /* ".bf" or ".ef" */ +#define C_EOS 102 /* end of structure */ +#define C_FILE 103 /* file name */ +#define C_LINE 104 /* dummy sclass for line number entry */ +#define C_ALIAS 105 /* duplicate tag */ +#define C_HIDDEN 106 /* special storage class for external */ + /* symbols in dmert public libraries */ + +/*------------------------------------------------------------------------*/ +/* SYMBOL TABLE ENTRIES */ +/*------------------------------------------------------------------------*/ + +#define SYMNMLEN 8 /* Number of characters in a symbol name */ +#define FILNMLEN 14 /* Number of characters in a file name */ +#define DIMNUM 4 /* Number of array dimensions in auxiliary entry */ + + +struct syment +{ + union + { + char _n_name[SYMNMLEN]; /* old COFF version */ + struct + { + long _n_zeroes; /* new == 0 */ + long _n_offset; /* offset into string table */ + } _n_n; + char *_n_nptr[2]; /* allows for overlaying */ + } _n; + long n_value; /* value of symbol */ + short n_scnum; /* section number */ + unsigned short n_type; /* type and derived type */ + char n_sclass; /* storage class */ + char n_numaux; /* number of aux. entries */ +}; + +#define n_name _n._n_name +#define n_nptr _n._n_nptr[1] +#define n_zeroes _n._n_n._n_zeroes +#define n_offset _n._n_n._n_offset + +/*------------------------------------------------------------------------*/ +/* Relocatable symbols have a section number of the */ +/* section in which they are defined. Otherwise, section */ +/* numbers have the following meanings: */ +/*------------------------------------------------------------------------*/ +#define N_UNDEF 0 /* undefined symbol */ +#define N_ABS -1 /* value of symbol is absolute */ +#define N_DEBUG -2 /* special debugging symbol */ +#define N_TV (unsigned short)-3 /* needs transfer vector (preload) */ +#define P_TV (unsigned short)-4 /* needs transfer vector (postload) */ + + +/*------------------------------------------------------------------------*/ +/* The fundamental type of a symbol packed into the low */ +/* 4 bits of the word. */ +/*------------------------------------------------------------------------*/ +#define _EF ".ef" + +#define T_NULL 0 /* no type info */ +#define T_ARG 1 /* function argument (only used by compiler) */ +#define T_CHAR 2 /* character */ +#define T_SHORT 3 /* short integer */ +#define T_INT 4 /* integer */ +#define T_LONG 5 /* long integer */ +#define T_FLOAT 6 /* floating point */ +#define T_DOUBLE 7 /* double word */ +#define T_STRUCT 8 /* structure */ +#define T_UNION 9 /* union */ +#define T_ENUM 10 /* enumeration */ +#define T_MOE 11 /* member of enumeration */ +#define T_UCHAR 12 /* unsigned character */ +#define T_USHORT 13 /* unsigned short */ +#define T_UINT 14 /* unsigned integer */ +#define T_ULONG 15 /* unsigned long */ + +/*------------------------------------------------------------------------*/ +/* derived types are: */ +/*------------------------------------------------------------------------*/ +#define DT_NON 0 /* no derived type */ +#define DT_PTR 1 /* pointer */ +#define DT_FCN 2 /* function */ +#define DT_ARY 3 /* array */ + +#define MKTYPE(basic, d1,d2,d3,d4,d5,d6) \ + ((basic) | ((d1) << 4) | ((d2) << 6) | ((d3) << 8) |\ + ((d4) << 10) | ((d5) << 12) | ((d6) << 14)) + +/*------------------------------------------------------------------------*/ +/* type packing constants and macros */ +/*------------------------------------------------------------------------*/ +#define N_BTMASK_COFF 017 +#define N_TMASK_COFF 060 +#define N_TMASK1_COFF 0300 +#define N_TMASK2_COFF 0360 +#define N_BTSHFT_COFF 4 +#define N_TSHIFT_COFF 2 + +#define BTYPE_COFF(x) ((x) & N_BTMASK_COFF) +#define ISINT(x) (((x) >= T_CHAR && (x) <= T_LONG) || \ + ((x) >= T_UCHAR && (x) <= T_ULONG) || (x) == T_ENUM) +#define ISFLT_COFF(x) ((x) == T_DOUBLE || (x) == T_FLOAT) +#define ISPTR_COFF(x) (((x) & N_TMASK_COFF) == (DT_PTR << N_BTSHFT_COFF)) +#define ISFCN_COFF(x) (((x) & N_TMASK_COFF) == (DT_FCN << N_BTSHFT_COFF)) +#define ISARY_COFF(x) (((x) & N_TMASK_COFF) == (DT_ARY << N_BTSHFT_COFF)) +#define ISTAG_COFF(x) ((x)==C_STRTAG || (x)==C_UNTAG || (x)==C_ENTAG) + +#define INCREF_COFF(x) ((((x)&~N_BTMASK_COFF)<>N_TSHIFT_COFF)&~N_BTMASK_COFF)|((x)&N_BTMASK_COFF)) + + +/*------------------------------------------------------------------------*/ +/* AUXILIARY SYMBOL ENTRY */ +/*------------------------------------------------------------------------*/ +union auxent +{ + struct + { + long x_tagndx; /* str, un, or enum tag indx */ + union + { + struct + { + unsigned short x_lnno; /* declaration line number */ + unsigned short x_size; /* str, union, array size */ + } x_lnsz; + long x_fsize; /* size of function */ + } x_misc; + union + { + struct /* if ISFCN, tag, or .bb */ + { + long x_lnnoptr; /* ptr to fcn line # */ + long x_endndx; /* entry ndx past block end */ + } x_fcn; + struct /* if ISARY, up to 4 dimen. */ + { + unsigned short x_dimen[DIMNUM]; + } x_ary; + } x_fcnary; + unsigned short x_regcount; /* number of registers used by func */ + } x_sym; + struct + { + char x_fname[FILNMLEN]; + } x_file; + struct + { + long x_scnlen; /* section length */ + unsigned short x_nreloc; /* number of relocation entries */ + unsigned short x_nlinno; /* number of line numbers */ + } x_scn; +}; + +#define SYMENT struct syment +#define SYMESZ 18 /* sizeof(SYMENT) */ + +#define AUXENT union auxent +#define AUXESZ 18 /* sizeof(AUXENT) */ + +/*------------------------------------------------------------------------*/ +/* NAMES OF "SPECIAL" SYMBOLS */ +/*------------------------------------------------------------------------*/ +#define _STEXT ".text" +#define _ETEXT "etext" +#define _SDATA ".data" +#define _EDATA "edata" +#define _SBSS ".bss" +#define _END "end" +#define _CINITPTR "cinit" + +/*--------------------------------------------------------------------------*/ +/* ENTRY POINT SYMBOLS */ +/*--------------------------------------------------------------------------*/ +#define _START "_start" +#define _MAIN "_main" + /* _CSTART "_c_int00" (defined in params.h) */ + + +#define _TVORIG "_tvorig" +#define _TORIGIN "_torigin" +#define _DORIGIN "_dorigin" + +#define _SORIGIN "_sorigin" diff --git a/programs/src/tcc/config.h b/programs/src/tcc/config.h new file mode 100644 index 0000000..30ced40 --- /dev/null +++ b/programs/src/tcc/config.h @@ -0,0 +1,42 @@ +/* + * config.h + * TCC configuration for MontaukOS + * Copyright (c) 2026 Daniel Hammer +*/ + +#ifndef TCC_CONFIG_H +#define TCC_CONFIG_H + +#define TCC_VERSION "0.9.28" +#define TCC_TARGET_X86_64 1 +#define CONFIG_TCC_STATIC 1 + +/* No backtrace, bcheck, or run support on MontaukOS */ +#define CONFIG_TCC_BACKTRACE 0 +#undef CONFIG_TCC_BCHECK + +/* Paths on MontaukOS ramdisk */ +#define CONFIG_TCCDIR "0:/lib/tcc" +#define CONFIG_TCC_SYSINCLUDEPATHS "0:/lib/tcc/include" +#define CONFIG_TCC_LIBPATHS "0:/lib/tcc/lib" +#define CONFIG_TCC_CRTPREFIX "0:/lib/tcc/lib" +#define CONFIG_TCC_ELFINTERP "" + +/* We are not native -- no -run support */ +#undef TCC_IS_NATIVE + +/* Disable unused features */ +#define CONFIG_TCC_PREDEFS 0 +#define CONFIG_TCC_SEMLOCK 0 + +/* No libtcc1 runtime library needed */ +#define TCC_LIBTCC1 "" + +/* No libgcc needed */ +#undef TCC_LIBGCC + +/* MontaukOS uses ELF, not PE or Mach-O */ +#undef TCC_TARGET_PE +#undef TCC_TARGET_MACHO + +#endif /* TCC_CONFIG_H */ diff --git a/programs/src/tcc/crt/crt1.c b/programs/src/tcc/crt/crt1.c new file mode 100644 index 0000000..9fe0961 --- /dev/null +++ b/programs/src/tcc/crt/crt1.c @@ -0,0 +1,77 @@ +/* + * crt1.c + * C runtime startup for TCC-compiled programs on MontaukOS + * Copyright (c) 2026 Daniel Hammer + * + * Provides _start, which: + * 1. Gets command-line arguments from kernel + * 2. Parses them into argc/argv + * 3. Calls main(argc, argv) + * 4. Calls exit(return value) +*/ + +/* Syscall wrappers (inline asm, no header dependencies) */ + +static inline long _sys0(long nr) { + long ret; + __asm__ volatile("syscall" : "=a"(ret) : "a"(nr) + : "rcx", "r11", "rdi", "rsi", "rdx", "r8", "r9", "r10", "memory"); + return ret; +} + +static inline long _sys1(long nr, long a1) { + long ret; + __asm__ volatile( + "mov %[a1], %%rdi\n\t" + "syscall" + : "=a"(ret) + : "a"(nr), [a1] "r"(a1) + : "rcx", "r11", "rdi", "rsi", "rdx", "r8", "r9", "r10", "memory"); + return ret; +} + +static inline long _sys2(long nr, long a1, long a2) { + long ret; + __asm__ volatile( + "mov %[a1], %%rdi\n\t" + "mov %[a2], %%rsi\n\t" + "syscall" + : "=a"(ret) + : "a"(nr), [a1] "r"(a1), [a2] "r"(a2) + : "rcx", "r11", "rdi", "rsi", "rdx", "r8", "r9", "r10", "memory"); + return ret; +} + +#define SYS_EXIT 0 +#define SYS_GETARGS 25 + +extern int main(int argc, char **argv); + +void _start(void) { + char argbuf[256]; + int len = (int)_sys2(SYS_GETARGS, (long)argbuf, (long)sizeof(argbuf)); + + char *argv[32]; + int argc = 0; + + /* argv[0] = program name */ + argv[argc++] = "prog"; + + if (len > 0) { + if (len > 255) len = 255; + argbuf[len] = '\0'; + char *p = argbuf; + while (*p && argc < 31) { + while (*p == ' ') p++; + if (*p == '\0') break; + argv[argc++] = p; + while (*p && *p != ' ') p++; + if (*p) *p++ = '\0'; + } + } + argv[argc] = (void*)0; + + int ret = main(argc, argv); + _sys1(SYS_EXIT, (long)ret); + __builtin_unreachable(); +} diff --git a/programs/src/tcc/crt/crti.c b/programs/src/tcc/crt/crti.c new file mode 100644 index 0000000..364629e --- /dev/null +++ b/programs/src/tcc/crt/crti.c @@ -0,0 +1,7 @@ +/* + * crti.c + * Init section prologue (minimal for MontaukOS) + * Copyright (c) 2026 Daniel Hammer +*/ + +/* Empty -- MontaukOS userspace has no global constructors */ diff --git a/programs/src/tcc/crt/crtn.c b/programs/src/tcc/crt/crtn.c new file mode 100644 index 0000000..77c866a --- /dev/null +++ b/programs/src/tcc/crt/crtn.c @@ -0,0 +1,7 @@ +/* + * crtn.c + * Init section epilogue (minimal for MontaukOS) + * Copyright (c) 2026 Daniel Hammer +*/ + +/* Empty -- MontaukOS userspace has no global destructors */ diff --git a/programs/src/tcc/dwarf.h b/programs/src/tcc/dwarf.h new file mode 100644 index 0000000..c961bc3 --- /dev/null +++ b/programs/src/tcc/dwarf.h @@ -0,0 +1,1046 @@ +/* This file defines standard DWARF types, structures, and macros. + Copyright (C) 2000-2011, 2014, 2016, 2017, 2018 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + elfutils 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 + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see . */ + +#ifndef _DWARF_H +#define _DWARF_H 1 + +/* DWARF Unit Header Types. */ +enum + { + DW_UT_compile = 0x01, + DW_UT_type = 0x02, + DW_UT_partial = 0x03, + DW_UT_skeleton = 0x04, + DW_UT_split_compile = 0x05, + DW_UT_split_type = 0x06, + + DW_UT_lo_user = 0x80, + DW_UT_hi_user = 0xff + }; + +/* DWARF tags. */ +enum + { + DW_TAG_array_type = 0x01, + DW_TAG_class_type = 0x02, + DW_TAG_entry_point = 0x03, + DW_TAG_enumeration_type = 0x04, + DW_TAG_formal_parameter = 0x05, + /* 0x06 reserved. */ + /* 0x07 reserved. */ + DW_TAG_imported_declaration = 0x08, + /* 0x09 reserved. */ + DW_TAG_label = 0x0a, + DW_TAG_lexical_block = 0x0b, + /* 0x0c reserved. */ + DW_TAG_member = 0x0d, + /* 0x0e reserved. */ + DW_TAG_pointer_type = 0x0f, + DW_TAG_reference_type = 0x10, + DW_TAG_compile_unit = 0x11, + DW_TAG_string_type = 0x12, + DW_TAG_structure_type = 0x13, + /* 0x14 reserved. */ + DW_TAG_subroutine_type = 0x15, + DW_TAG_typedef = 0x16, + DW_TAG_union_type = 0x17, + DW_TAG_unspecified_parameters = 0x18, + DW_TAG_variant = 0x19, + DW_TAG_common_block = 0x1a, + DW_TAG_common_inclusion = 0x1b, + DW_TAG_inheritance = 0x1c, + DW_TAG_inlined_subroutine = 0x1d, + DW_TAG_module = 0x1e, + DW_TAG_ptr_to_member_type = 0x1f, + DW_TAG_set_type = 0x20, + DW_TAG_subrange_type = 0x21, + DW_TAG_with_stmt = 0x22, + DW_TAG_access_declaration = 0x23, + DW_TAG_base_type = 0x24, + DW_TAG_catch_block = 0x25, + DW_TAG_const_type = 0x26, + DW_TAG_constant = 0x27, + DW_TAG_enumerator = 0x28, + DW_TAG_file_type = 0x29, + DW_TAG_friend = 0x2a, + DW_TAG_namelist = 0x2b, + DW_TAG_namelist_item = 0x2c, + DW_TAG_packed_type = 0x2d, + DW_TAG_subprogram = 0x2e, + DW_TAG_template_type_parameter = 0x2f, + DW_TAG_template_value_parameter = 0x30, + DW_TAG_thrown_type = 0x31, + DW_TAG_try_block = 0x32, + DW_TAG_variant_part = 0x33, + DW_TAG_variable = 0x34, + DW_TAG_volatile_type = 0x35, + DW_TAG_dwarf_procedure = 0x36, + DW_TAG_restrict_type = 0x37, + DW_TAG_interface_type = 0x38, + DW_TAG_namespace = 0x39, + DW_TAG_imported_module = 0x3a, + DW_TAG_unspecified_type = 0x3b, + DW_TAG_partial_unit = 0x3c, + DW_TAG_imported_unit = 0x3d, + /* 0x3e reserved. Was DW_TAG_mutable_type. */ + DW_TAG_condition = 0x3f, + DW_TAG_shared_type = 0x40, + DW_TAG_type_unit = 0x41, + DW_TAG_rvalue_reference_type = 0x42, + DW_TAG_template_alias = 0x43, + DW_TAG_coarray_type = 0x44, + DW_TAG_generic_subrange = 0x45, + DW_TAG_dynamic_type = 0x46, + DW_TAG_atomic_type = 0x47, + DW_TAG_call_site = 0x48, + DW_TAG_call_site_parameter = 0x49, + DW_TAG_skeleton_unit = 0x4a, + DW_TAG_immutable_type = 0x4b, + + DW_TAG_lo_user = 0x4080, + + DW_TAG_MIPS_loop = 0x4081, + DW_TAG_format_label = 0x4101, + DW_TAG_function_template = 0x4102, + DW_TAG_class_template = 0x4103, + + DW_TAG_GNU_BINCL = 0x4104, + DW_TAG_GNU_EINCL = 0x4105, + + DW_TAG_GNU_template_template_param = 0x4106, + DW_TAG_GNU_template_parameter_pack = 0x4107, + DW_TAG_GNU_formal_parameter_pack = 0x4108, + DW_TAG_GNU_call_site = 0x4109, + DW_TAG_GNU_call_site_parameter = 0x410a, + + DW_TAG_hi_user = 0xffff + }; + + +/* Children determination encodings. */ +enum + { + DW_CHILDREN_no = 0, + DW_CHILDREN_yes = 1 + }; + + +/* DWARF attributes encodings. */ +enum + { + DW_AT_sibling = 0x01, + DW_AT_location = 0x02, + DW_AT_name = 0x03, + /* 0x04 reserved. */ + /* 0x05 reserved. */ + /* 0x06 reserved. */ + /* 0x07 reserved. */ + /* 0x08 reserved. */ + DW_AT_ordering = 0x09, + /* 0x0a reserved. */ + DW_AT_byte_size = 0x0b, + DW_AT_bit_offset = 0x0c, /* Deprecated in DWARF4. */ + DW_AT_bit_size = 0x0d, + /* 0x0e reserved. */ + /* 0x0f reserved. */ + DW_AT_stmt_list = 0x10, + DW_AT_low_pc = 0x11, + DW_AT_high_pc = 0x12, + DW_AT_language = 0x13, + /* 0x14 reserved. */ + DW_AT_discr = 0x15, + DW_AT_discr_value = 0x16, + DW_AT_visibility = 0x17, + DW_AT_import = 0x18, + DW_AT_string_length = 0x19, + DW_AT_common_reference = 0x1a, + DW_AT_comp_dir = 0x1b, + DW_AT_const_value = 0x1c, + DW_AT_containing_type = 0x1d, + DW_AT_default_value = 0x1e, + /* 0x1f reserved. */ + DW_AT_inline = 0x20, + DW_AT_is_optional = 0x21, + DW_AT_lower_bound = 0x22, + /* 0x23 reserved. */ + /* 0x24 reserved. */ + DW_AT_producer = 0x25, + /* 0x26 reserved. */ + DW_AT_prototyped = 0x27, + /* 0x28 reserved. */ + /* 0x29 reserved. */ + DW_AT_return_addr = 0x2a, + /* 0x2b reserved. */ + DW_AT_start_scope = 0x2c, + /* 0x2d reserved. */ + DW_AT_bit_stride = 0x2e, + DW_AT_upper_bound = 0x2f, + /* 0x30 reserved. */ + DW_AT_abstract_origin = 0x31, + DW_AT_accessibility = 0x32, + DW_AT_address_class = 0x33, + DW_AT_artificial = 0x34, + DW_AT_base_types = 0x35, + DW_AT_calling_convention = 0x36, + DW_AT_count = 0x37, + DW_AT_data_member_location = 0x38, + DW_AT_decl_column = 0x39, + DW_AT_decl_file = 0x3a, + DW_AT_decl_line = 0x3b, + DW_AT_declaration = 0x3c, + DW_AT_discr_list = 0x3d, + DW_AT_encoding = 0x3e, + DW_AT_external = 0x3f, + DW_AT_frame_base = 0x40, + DW_AT_friend = 0x41, + DW_AT_identifier_case = 0x42, + DW_AT_macro_info = 0x43, /* Deprecated in DWARF5. */ + DW_AT_namelist_item = 0x44, + DW_AT_priority = 0x45, + DW_AT_segment = 0x46, + DW_AT_specification = 0x47, + DW_AT_static_link = 0x48, + DW_AT_type = 0x49, + DW_AT_use_location = 0x4a, + DW_AT_variable_parameter = 0x4b, + DW_AT_virtuality = 0x4c, + DW_AT_vtable_elem_location = 0x4d, + DW_AT_allocated = 0x4e, + DW_AT_associated = 0x4f, + DW_AT_data_location = 0x50, + DW_AT_byte_stride = 0x51, + DW_AT_entry_pc = 0x52, + DW_AT_use_UTF8 = 0x53, + DW_AT_extension = 0x54, + DW_AT_ranges = 0x55, + DW_AT_trampoline = 0x56, + DW_AT_call_column = 0x57, + DW_AT_call_file = 0x58, + DW_AT_call_line = 0x59, + DW_AT_description = 0x5a, + DW_AT_binary_scale = 0x5b, + DW_AT_decimal_scale = 0x5c, + DW_AT_small = 0x5d, + DW_AT_decimal_sign = 0x5e, + DW_AT_digit_count = 0x5f, + DW_AT_picture_string = 0x60, + DW_AT_mutable = 0x61, + DW_AT_threads_scaled = 0x62, + DW_AT_explicit = 0x63, + DW_AT_object_pointer = 0x64, + DW_AT_endianity = 0x65, + DW_AT_elemental = 0x66, + DW_AT_pure = 0x67, + DW_AT_recursive = 0x68, + DW_AT_signature = 0x69, + DW_AT_main_subprogram = 0x6a, + DW_AT_data_bit_offset = 0x6b, + DW_AT_const_expr = 0x6c, + DW_AT_enum_class = 0x6d, + DW_AT_linkage_name = 0x6e, + DW_AT_string_length_bit_size = 0x6f, + DW_AT_string_length_byte_size = 0x70, + DW_AT_rank = 0x71, + DW_AT_str_offsets_base = 0x72, + DW_AT_addr_base = 0x73, + DW_AT_rnglists_base = 0x74, + /* 0x75 reserved. */ + DW_AT_dwo_name = 0x76, + DW_AT_reference = 0x77, + DW_AT_rvalue_reference = 0x78, + DW_AT_macros = 0x79, + DW_AT_call_all_calls = 0x7a, + DW_AT_call_all_source_calls = 0x7b, + DW_AT_call_all_tail_calls = 0x7c, + DW_AT_call_return_pc = 0x7d, + DW_AT_call_value = 0x7e, + DW_AT_call_origin = 0x7f, + DW_AT_call_parameter = 0x80, + DW_AT_call_pc = 0x81, + DW_AT_call_tail_call = 0x82, + DW_AT_call_target = 0x83, + DW_AT_call_target_clobbered = 0x84, + DW_AT_call_data_location = 0x85, + DW_AT_call_data_value = 0x86, + DW_AT_noreturn = 0x87, + DW_AT_alignment = 0x88, + DW_AT_export_symbols = 0x89, + DW_AT_deleted = 0x8a, + DW_AT_defaulted = 0x8b, + DW_AT_loclists_base = 0x8c, + + DW_AT_lo_user = 0x2000, + + DW_AT_MIPS_fde = 0x2001, + DW_AT_MIPS_loop_begin = 0x2002, + DW_AT_MIPS_tail_loop_begin = 0x2003, + DW_AT_MIPS_epilog_begin = 0x2004, + DW_AT_MIPS_loop_unroll_factor = 0x2005, + DW_AT_MIPS_software_pipeline_depth = 0x2006, + DW_AT_MIPS_linkage_name = 0x2007, + DW_AT_MIPS_stride = 0x2008, + DW_AT_MIPS_abstract_name = 0x2009, + DW_AT_MIPS_clone_origin = 0x200a, + DW_AT_MIPS_has_inlines = 0x200b, + DW_AT_MIPS_stride_byte = 0x200c, + DW_AT_MIPS_stride_elem = 0x200d, + DW_AT_MIPS_ptr_dopetype = 0x200e, + DW_AT_MIPS_allocatable_dopetype = 0x200f, + DW_AT_MIPS_assumed_shape_dopetype = 0x2010, + DW_AT_MIPS_assumed_size = 0x2011, + + /* GNU extensions. */ + DW_AT_sf_names = 0x2101, + DW_AT_src_info = 0x2102, + DW_AT_mac_info = 0x2103, + DW_AT_src_coords = 0x2104, + DW_AT_body_begin = 0x2105, + DW_AT_body_end = 0x2106, + DW_AT_GNU_vector = 0x2107, + DW_AT_GNU_guarded_by = 0x2108, + DW_AT_GNU_pt_guarded_by = 0x2109, + DW_AT_GNU_guarded = 0x210a, + DW_AT_GNU_pt_guarded = 0x210b, + DW_AT_GNU_locks_excluded = 0x210c, + DW_AT_GNU_exclusive_locks_required = 0x210d, + DW_AT_GNU_shared_locks_required = 0x210e, + DW_AT_GNU_odr_signature = 0x210f, + DW_AT_GNU_template_name = 0x2110, + DW_AT_GNU_call_site_value = 0x2111, + DW_AT_GNU_call_site_data_value = 0x2112, + DW_AT_GNU_call_site_target = 0x2113, + DW_AT_GNU_call_site_target_clobbered = 0x2114, + DW_AT_GNU_tail_call = 0x2115, + DW_AT_GNU_all_tail_call_sites = 0x2116, + DW_AT_GNU_all_call_sites = 0x2117, + DW_AT_GNU_all_source_call_sites = 0x2118, + DW_AT_GNU_locviews = 0x2137, + DW_AT_GNU_entry_view = 0x2138, + DW_AT_GNU_macros = 0x2119, + DW_AT_GNU_deleted = 0x211a, + /* GNU Debug Fission extensions. */ + DW_AT_GNU_dwo_name = 0x2130, + DW_AT_GNU_dwo_id = 0x2131, + DW_AT_GNU_ranges_base = 0x2132, + DW_AT_GNU_addr_base = 0x2133, + DW_AT_GNU_pubnames = 0x2134, + DW_AT_GNU_pubtypes = 0x2135, + + /* https://gcc.gnu.org/wiki/DW_AT_GNU_numerator_denominator */ + DW_AT_GNU_numerator = 0x2303, + DW_AT_GNU_denominator = 0x2304, + /* https://gcc.gnu.org/wiki/DW_AT_GNU_bias */ + DW_AT_GNU_bias = 0x2305, + + DW_AT_hi_user = 0x3fff + }; + +/* Old unofficially attribute names. Should not be used. + Will not appear in known-dwarf.h */ + +/* DWARF1 array subscripts and element data types. */ +#define DW_AT_subscr_data 0x0a +/* DWARF1 enumeration literals. */ +#define DW_AT_element_list 0x0f +/* DWARF1 reference for variable to member structure, class or union. */ +#define DW_AT_member 0x14 + +/* DWARF form encodings. */ +enum + { + DW_FORM_addr = 0x01, + DW_FORM_block2 = 0x03, + DW_FORM_block4 = 0x04, + DW_FORM_data2 = 0x05, + DW_FORM_data4 = 0x06, + DW_FORM_data8 = 0x07, + DW_FORM_string = 0x08, + DW_FORM_block = 0x09, + DW_FORM_block1 = 0x0a, + DW_FORM_data1 = 0x0b, + DW_FORM_flag = 0x0c, + DW_FORM_sdata = 0x0d, + DW_FORM_strp = 0x0e, + DW_FORM_udata = 0x0f, + DW_FORM_ref_addr = 0x10, + DW_FORM_ref1 = 0x11, + DW_FORM_ref2 = 0x12, + DW_FORM_ref4 = 0x13, + DW_FORM_ref8 = 0x14, + DW_FORM_ref_udata = 0x15, + DW_FORM_indirect = 0x16, + DW_FORM_sec_offset = 0x17, + DW_FORM_exprloc = 0x18, + DW_FORM_flag_present = 0x19, + DW_FORM_strx = 0x1a, + DW_FORM_addrx = 0x1b, + DW_FORM_ref_sup4 = 0x1c, + DW_FORM_strp_sup = 0x1d, + DW_FORM_data16 = 0x1e, + DW_FORM_line_strp = 0x1f, + DW_FORM_ref_sig8 = 0x20, + DW_FORM_implicit_const = 0x21, + DW_FORM_loclistx = 0x22, + DW_FORM_rnglistx = 0x23, + DW_FORM_ref_sup8 = 0x24, + DW_FORM_strx1 = 0x25, + DW_FORM_strx2 = 0x26, + DW_FORM_strx3 = 0x27, + DW_FORM_strx4 = 0x28, + DW_FORM_addrx1 = 0x29, + DW_FORM_addrx2 = 0x2a, + DW_FORM_addrx3 = 0x2b, + DW_FORM_addrx4 = 0x2c, + + /* GNU Debug Fission extensions. */ + DW_FORM_GNU_addr_index = 0x1f01, + DW_FORM_GNU_str_index = 0x1f02, + + DW_FORM_GNU_ref_alt = 0x1f20, /* offset in alternate .debuginfo. */ + DW_FORM_GNU_strp_alt = 0x1f21 /* offset in alternate .debug_str. */ + }; + + +/* DWARF location operation encodings. */ +enum + { + DW_OP_addr = 0x03, /* Constant address. */ + DW_OP_deref = 0x06, + DW_OP_const1u = 0x08, /* Unsigned 1-byte constant. */ + DW_OP_const1s = 0x09, /* Signed 1-byte constant. */ + DW_OP_const2u = 0x0a, /* Unsigned 2-byte constant. */ + DW_OP_const2s = 0x0b, /* Signed 2-byte constant. */ + DW_OP_const4u = 0x0c, /* Unsigned 4-byte constant. */ + DW_OP_const4s = 0x0d, /* Signed 4-byte constant. */ + DW_OP_const8u = 0x0e, /* Unsigned 8-byte constant. */ + DW_OP_const8s = 0x0f, /* Signed 8-byte constant. */ + DW_OP_constu = 0x10, /* Unsigned LEB128 constant. */ + DW_OP_consts = 0x11, /* Signed LEB128 constant. */ + DW_OP_dup = 0x12, + DW_OP_drop = 0x13, + DW_OP_over = 0x14, + DW_OP_pick = 0x15, /* 1-byte stack index. */ + DW_OP_swap = 0x16, + DW_OP_rot = 0x17, + DW_OP_xderef = 0x18, + DW_OP_abs = 0x19, + DW_OP_and = 0x1a, + DW_OP_div = 0x1b, + DW_OP_minus = 0x1c, + DW_OP_mod = 0x1d, + DW_OP_mul = 0x1e, + DW_OP_neg = 0x1f, + DW_OP_not = 0x20, + DW_OP_or = 0x21, + DW_OP_plus = 0x22, + DW_OP_plus_uconst = 0x23, /* Unsigned LEB128 addend. */ + DW_OP_shl = 0x24, + DW_OP_shr = 0x25, + DW_OP_shra = 0x26, + DW_OP_xor = 0x27, + DW_OP_bra = 0x28, /* Signed 2-byte constant. */ + DW_OP_eq = 0x29, + DW_OP_ge = 0x2a, + DW_OP_gt = 0x2b, + DW_OP_le = 0x2c, + DW_OP_lt = 0x2d, + DW_OP_ne = 0x2e, + DW_OP_skip = 0x2f, /* Signed 2-byte constant. */ + DW_OP_lit0 = 0x30, /* Literal 0. */ + DW_OP_lit1 = 0x31, /* Literal 1. */ + DW_OP_lit2 = 0x32, /* Literal 2. */ + DW_OP_lit3 = 0x33, /* Literal 3. */ + DW_OP_lit4 = 0x34, /* Literal 4. */ + DW_OP_lit5 = 0x35, /* Literal 5. */ + DW_OP_lit6 = 0x36, /* Literal 6. */ + DW_OP_lit7 = 0x37, /* Literal 7. */ + DW_OP_lit8 = 0x38, /* Literal 8. */ + DW_OP_lit9 = 0x39, /* Literal 9. */ + DW_OP_lit10 = 0x3a, /* Literal 10. */ + DW_OP_lit11 = 0x3b, /* Literal 11. */ + DW_OP_lit12 = 0x3c, /* Literal 12. */ + DW_OP_lit13 = 0x3d, /* Literal 13. */ + DW_OP_lit14 = 0x3e, /* Literal 14. */ + DW_OP_lit15 = 0x3f, /* Literal 15. */ + DW_OP_lit16 = 0x40, /* Literal 16. */ + DW_OP_lit17 = 0x41, /* Literal 17. */ + DW_OP_lit18 = 0x42, /* Literal 18. */ + DW_OP_lit19 = 0x43, /* Literal 19. */ + DW_OP_lit20 = 0x44, /* Literal 20. */ + DW_OP_lit21 = 0x45, /* Literal 21. */ + DW_OP_lit22 = 0x46, /* Literal 22. */ + DW_OP_lit23 = 0x47, /* Literal 23. */ + DW_OP_lit24 = 0x48, /* Literal 24. */ + DW_OP_lit25 = 0x49, /* Literal 25. */ + DW_OP_lit26 = 0x4a, /* Literal 26. */ + DW_OP_lit27 = 0x4b, /* Literal 27. */ + DW_OP_lit28 = 0x4c, /* Literal 28. */ + DW_OP_lit29 = 0x4d, /* Literal 29. */ + DW_OP_lit30 = 0x4e, /* Literal 30. */ + DW_OP_lit31 = 0x4f, /* Literal 31. */ + DW_OP_reg0 = 0x50, /* Register 0. */ + DW_OP_reg1 = 0x51, /* Register 1. */ + DW_OP_reg2 = 0x52, /* Register 2. */ + DW_OP_reg3 = 0x53, /* Register 3. */ + DW_OP_reg4 = 0x54, /* Register 4. */ + DW_OP_reg5 = 0x55, /* Register 5. */ + DW_OP_reg6 = 0x56, /* Register 6. */ + DW_OP_reg7 = 0x57, /* Register 7. */ + DW_OP_reg8 = 0x58, /* Register 8. */ + DW_OP_reg9 = 0x59, /* Register 9. */ + DW_OP_reg10 = 0x5a, /* Register 10. */ + DW_OP_reg11 = 0x5b, /* Register 11. */ + DW_OP_reg12 = 0x5c, /* Register 12. */ + DW_OP_reg13 = 0x5d, /* Register 13. */ + DW_OP_reg14 = 0x5e, /* Register 14. */ + DW_OP_reg15 = 0x5f, /* Register 15. */ + DW_OP_reg16 = 0x60, /* Register 16. */ + DW_OP_reg17 = 0x61, /* Register 17. */ + DW_OP_reg18 = 0x62, /* Register 18. */ + DW_OP_reg19 = 0x63, /* Register 19. */ + DW_OP_reg20 = 0x64, /* Register 20. */ + DW_OP_reg21 = 0x65, /* Register 21. */ + DW_OP_reg22 = 0x66, /* Register 22. */ + DW_OP_reg23 = 0x67, /* Register 24. */ + DW_OP_reg24 = 0x68, /* Register 24. */ + DW_OP_reg25 = 0x69, /* Register 25. */ + DW_OP_reg26 = 0x6a, /* Register 26. */ + DW_OP_reg27 = 0x6b, /* Register 27. */ + DW_OP_reg28 = 0x6c, /* Register 28. */ + DW_OP_reg29 = 0x6d, /* Register 29. */ + DW_OP_reg30 = 0x6e, /* Register 30. */ + DW_OP_reg31 = 0x6f, /* Register 31. */ + DW_OP_breg0 = 0x70, /* Base register 0. */ + DW_OP_breg1 = 0x71, /* Base register 1. */ + DW_OP_breg2 = 0x72, /* Base register 2. */ + DW_OP_breg3 = 0x73, /* Base register 3. */ + DW_OP_breg4 = 0x74, /* Base register 4. */ + DW_OP_breg5 = 0x75, /* Base register 5. */ + DW_OP_breg6 = 0x76, /* Base register 6. */ + DW_OP_breg7 = 0x77, /* Base register 7. */ + DW_OP_breg8 = 0x78, /* Base register 8. */ + DW_OP_breg9 = 0x79, /* Base register 9. */ + DW_OP_breg10 = 0x7a, /* Base register 10. */ + DW_OP_breg11 = 0x7b, /* Base register 11. */ + DW_OP_breg12 = 0x7c, /* Base register 12. */ + DW_OP_breg13 = 0x7d, /* Base register 13. */ + DW_OP_breg14 = 0x7e, /* Base register 14. */ + DW_OP_breg15 = 0x7f, /* Base register 15. */ + DW_OP_breg16 = 0x80, /* Base register 16. */ + DW_OP_breg17 = 0x81, /* Base register 17. */ + DW_OP_breg18 = 0x82, /* Base register 18. */ + DW_OP_breg19 = 0x83, /* Base register 19. */ + DW_OP_breg20 = 0x84, /* Base register 20. */ + DW_OP_breg21 = 0x85, /* Base register 21. */ + DW_OP_breg22 = 0x86, /* Base register 22. */ + DW_OP_breg23 = 0x87, /* Base register 23. */ + DW_OP_breg24 = 0x88, /* Base register 24. */ + DW_OP_breg25 = 0x89, /* Base register 25. */ + DW_OP_breg26 = 0x8a, /* Base register 26. */ + DW_OP_breg27 = 0x8b, /* Base register 27. */ + DW_OP_breg28 = 0x8c, /* Base register 28. */ + DW_OP_breg29 = 0x8d, /* Base register 29. */ + DW_OP_breg30 = 0x8e, /* Base register 30. */ + DW_OP_breg31 = 0x8f, /* Base register 31. */ + DW_OP_regx = 0x90, /* Unsigned LEB128 register. */ + DW_OP_fbreg = 0x91, /* Signed LEB128 offset. */ + DW_OP_bregx = 0x92, /* ULEB128 register followed by SLEB128 off. */ + DW_OP_piece = 0x93, /* ULEB128 size of piece addressed. */ + DW_OP_deref_size = 0x94, /* 1-byte size of data retrieved. */ + DW_OP_xderef_size = 0x95, /* 1-byte size of data retrieved. */ + DW_OP_nop = 0x96, + DW_OP_push_object_address = 0x97, + DW_OP_call2 = 0x98, + DW_OP_call4 = 0x99, + DW_OP_call_ref = 0x9a, + DW_OP_form_tls_address = 0x9b,/* TLS offset to address in current thread */ + DW_OP_call_frame_cfa = 0x9c,/* CFA as determined by CFI. */ + DW_OP_bit_piece = 0x9d, /* ULEB128 size and ULEB128 offset in bits. */ + DW_OP_implicit_value = 0x9e, /* DW_FORM_block follows opcode. */ + DW_OP_stack_value = 0x9f, /* No operands, special like DW_OP_piece. */ + + DW_OP_implicit_pointer = 0xa0, + DW_OP_addrx = 0xa1, + DW_OP_constx = 0xa2, + DW_OP_entry_value = 0xa3, + DW_OP_const_type = 0xa4, + DW_OP_regval_type = 0xa5, + DW_OP_deref_type = 0xa6, + DW_OP_xderef_type = 0xa7, + DW_OP_convert = 0xa8, + DW_OP_reinterpret = 0xa9, + + /* GNU extensions. */ + DW_OP_GNU_push_tls_address = 0xe0, + DW_OP_GNU_uninit = 0xf0, + DW_OP_GNU_encoded_addr = 0xf1, + DW_OP_GNU_implicit_pointer = 0xf2, + DW_OP_GNU_entry_value = 0xf3, + DW_OP_GNU_const_type = 0xf4, + DW_OP_GNU_regval_type = 0xf5, + DW_OP_GNU_deref_type = 0xf6, + DW_OP_GNU_convert = 0xf7, + DW_OP_GNU_reinterpret = 0xf9, + DW_OP_GNU_parameter_ref = 0xfa, + + /* GNU Debug Fission extensions. */ + DW_OP_GNU_addr_index = 0xfb, + DW_OP_GNU_const_index = 0xfc, + + DW_OP_GNU_variable_value = 0xfd, + + DW_OP_lo_user = 0xe0, /* Implementation-defined range start. */ + DW_OP_hi_user = 0xff /* Implementation-defined range end. */ + }; + + +/* DWARF base type encodings. */ +enum + { + DW_ATE_void = 0x0, + DW_ATE_address = 0x1, + DW_ATE_boolean = 0x2, + DW_ATE_complex_float = 0x3, + DW_ATE_float = 0x4, + DW_ATE_signed = 0x5, + DW_ATE_signed_char = 0x6, + DW_ATE_unsigned = 0x7, + DW_ATE_unsigned_char = 0x8, + DW_ATE_imaginary_float = 0x9, + DW_ATE_packed_decimal = 0xa, + DW_ATE_numeric_string = 0xb, + DW_ATE_edited = 0xc, + DW_ATE_signed_fixed = 0xd, + DW_ATE_unsigned_fixed = 0xe, + DW_ATE_decimal_float = 0xf, + DW_ATE_UTF = 0x10, + DW_ATE_UCS = 0x11, + DW_ATE_ASCII = 0x12, + + DW_ATE_lo_user = 0x80, + DW_ATE_hi_user = 0xff + }; + + +/* DWARF decimal sign encodings. */ +enum + { + DW_DS_unsigned = 1, + DW_DS_leading_overpunch = 2, + DW_DS_trailing_overpunch = 3, + DW_DS_leading_separate = 4, + DW_DS_trailing_separate = 5, + }; + + +/* DWARF endianity encodings. */ +enum + { + DW_END_default = 0, + DW_END_big = 1, + DW_END_little = 2, + + DW_END_lo_user = 0x40, + DW_END_hi_user = 0xff + }; + + +/* DWARF accessibility encodings. */ +enum + { + DW_ACCESS_public = 1, + DW_ACCESS_protected = 2, + DW_ACCESS_private = 3 + }; + + +/* DWARF visibility encodings. */ +enum + { + DW_VIS_local = 1, + DW_VIS_exported = 2, + DW_VIS_qualified = 3 + }; + + +/* DWARF virtuality encodings. */ +enum + { + DW_VIRTUALITY_none = 0, + DW_VIRTUALITY_virtual = 1, + DW_VIRTUALITY_pure_virtual = 2 + }; + + +/* DWARF language encodings. */ +enum + { + DW_LANG_C89 = 0x0001, /* ISO C:1989 */ + DW_LANG_C = 0x0002, /* C */ + DW_LANG_Ada83 = 0x0003, /* ISO Ada:1983 */ + DW_LANG_C_plus_plus = 0x0004, /* ISO C++:1998 */ + DW_LANG_Cobol74 = 0x0005, /* ISO Cobol:1974 */ + DW_LANG_Cobol85 = 0x0006, /* ISO Cobol:1985 */ + DW_LANG_Fortran77 = 0x0007, /* ISO FORTRAN 77 */ + DW_LANG_Fortran90 = 0x0008, /* ISO Fortran 90 */ + DW_LANG_Pascal83 = 0x0009, /* ISO Pascal:1983 */ + DW_LANG_Modula2 = 0x000a, /* ISO Modula-2:1996 */ + DW_LANG_Java = 0x000b, /* Java */ + DW_LANG_C99 = 0x000c, /* ISO C:1999 */ + DW_LANG_Ada95 = 0x000d, /* ISO Ada:1995 */ + DW_LANG_Fortran95 = 0x000e, /* ISO Fortran 95 */ + DW_LANG_PLI = 0x000f, /* ISO PL/1:1976 */ + DW_LANG_ObjC = 0x0010, /* Objective-C */ + DW_LANG_ObjC_plus_plus = 0x0011, /* Objective-C++ */ + DW_LANG_UPC = 0x0012, /* Unified Parallel C */ + DW_LANG_D = 0x0013, /* D */ + DW_LANG_Python = 0x0014, /* Python */ + DW_LANG_OpenCL = 0x0015, /* OpenCL */ + DW_LANG_Go = 0x0016, /* Go */ + DW_LANG_Modula3 = 0x0017, /* Modula-3 */ + DW_LANG_Haskell = 0x0018, /* Haskell */ + DW_LANG_C_plus_plus_03 = 0x0019, /* ISO C++:2003 */ + DW_LANG_C_plus_plus_11 = 0x001a, /* ISO C++:2011 */ + DW_LANG_OCaml = 0x001b, /* OCaml */ + DW_LANG_Rust = 0x001c, /* Rust */ + DW_LANG_C11 = 0x001d, /* ISO C:2011 */ + DW_LANG_Swift = 0x001e, /* Swift */ + DW_LANG_Julia = 0x001f, /* Julia */ + DW_LANG_Dylan = 0x0020, /* Dylan */ + DW_LANG_C_plus_plus_14 = 0x0021, /* ISO C++:2014 */ + DW_LANG_Fortran03 = 0x0022, /* ISO/IEC 1539-1:2004 */ + DW_LANG_Fortran08 = 0x0023, /* ISO/IEC 1539-1:2010 */ + DW_LANG_RenderScript = 0x0024, /* RenderScript Kernal Language */ + DW_LANG_BLISS = 0x0025, /* BLISS */ + + DW_LANG_lo_user = 0x8000, + DW_LANG_Mips_Assembler = 0x8001, /* Assembler */ + DW_LANG_hi_user = 0xffff + }; + +/* Old (typo) '1' != 'I'. */ +#define DW_LANG_PL1 DW_LANG_PLI + +/* DWARF identifier case encodings. */ +enum + { + DW_ID_case_sensitive = 0, + DW_ID_up_case = 1, + DW_ID_down_case = 2, + DW_ID_case_insensitive = 3 + }; + + +/* DWARF calling conventions encodings. + Used as values of DW_AT_calling_convention for subroutines + (normal, program or nocall) or structures, unions and class types + (normal, reference or value). */ +enum + { + DW_CC_normal = 0x1, + DW_CC_program = 0x2, + DW_CC_nocall = 0x3, + DW_CC_pass_by_reference = 0x4, + DW_CC_pass_by_value = 0x5, + DW_CC_lo_user = 0x40, + DW_CC_hi_user = 0xff + }; + + +/* DWARF inline encodings. */ +enum + { + DW_INL_not_inlined = 0, + DW_INL_inlined = 1, + DW_INL_declared_not_inlined = 2, + DW_INL_declared_inlined = 3 + }; + + +/* DWARF ordering encodings. */ +enum + { + DW_ORD_row_major = 0, + DW_ORD_col_major = 1 + }; + + +/* DWARF discriminant descriptor encodings. */ +enum + { + DW_DSC_label = 0, + DW_DSC_range = 1 + }; + +/* DWARF defaulted member function encodings. */ +enum + { + DW_DEFAULTED_no = 0, + DW_DEFAULTED_in_class = 1, + DW_DEFAULTED_out_of_class = 2 + }; + +/* DWARF line content descriptions. */ +enum + { + DW_LNCT_path = 0x1, + DW_LNCT_directory_index = 0x2, + DW_LNCT_timestamp = 0x3, + DW_LNCT_size = 0x4, + DW_LNCT_MD5 = 0x5, + DW_LNCT_lo_user = 0x2000, + DW_LNCT_hi_user = 0x3fff + }; + +/* DWARF standard opcode encodings. */ +enum + { + DW_LNS_copy = 1, + DW_LNS_advance_pc = 2, + DW_LNS_advance_line = 3, + DW_LNS_set_file = 4, + DW_LNS_set_column = 5, + DW_LNS_negate_stmt = 6, + DW_LNS_set_basic_block = 7, + DW_LNS_const_add_pc = 8, + DW_LNS_fixed_advance_pc = 9, + DW_LNS_set_prologue_end = 10, + DW_LNS_set_epilogue_begin = 11, + DW_LNS_set_isa = 12 + }; + + +/* DWARF extended opcode encodings. */ +enum + { + DW_LNE_end_sequence = 1, + DW_LNE_set_address = 2, + DW_LNE_define_file = 3, + DW_LNE_set_discriminator = 4, + + DW_LNE_lo_user = 128, + + DW_LNE_NVIDIA_inlined_call = 144, + DW_LNE_NVIDIA_set_function_name = 145, + + DW_LNE_hi_user = 255 + }; + + +/* DWARF macinfo type encodings. */ +enum + { + DW_MACINFO_define = 1, + DW_MACINFO_undef = 2, + DW_MACINFO_start_file = 3, + DW_MACINFO_end_file = 4, + DW_MACINFO_vendor_ext = 255 + }; + + +/* DWARF debug_macro type encodings. */ +enum + { + DW_MACRO_define = 0x01, + DW_MACRO_undef = 0x02, + DW_MACRO_start_file = 0x03, + DW_MACRO_end_file = 0x04, + DW_MACRO_define_strp = 0x05, + DW_MACRO_undef_strp = 0x06, + DW_MACRO_import = 0x07, + DW_MACRO_define_sup = 0x08, + DW_MACRO_undef_sup = 0x09, + DW_MACRO_import_sup = 0x0a, + DW_MACRO_define_strx = 0x0b, + DW_MACRO_undef_strx = 0x0c, + DW_MACRO_lo_user = 0xe0, + DW_MACRO_hi_user = 0xff + }; + +/* Old GNU extension names for DWARF5 debug_macro type encodings. + There are no equivalents for the supplementary object file (sup) + and indirect string references (strx). */ +#define DW_MACRO_GNU_define DW_MACRO_define +#define DW_MACRO_GNU_undef DW_MACRO_undef +#define DW_MACRO_GNU_start_file DW_MACRO_start_file +#define DW_MACRO_GNU_end_file DW_MACRO_end_file +#define DW_MACRO_GNU_define_indirect DW_MACRO_define_strp +#define DW_MACRO_GNU_undef_indirect DW_MACRO_undef_strp +#define DW_MACRO_GNU_transparent_include DW_MACRO_import +#define DW_MACRO_GNU_lo_user DW_MACRO_lo_user +#define DW_MACRO_GNU_hi_user DW_MACRO_hi_user + + +/* Range list entry encoding. */ +enum + { + DW_RLE_end_of_list = 0x0, + DW_RLE_base_addressx = 0x1, + DW_RLE_startx_endx = 0x2, + DW_RLE_startx_length = 0x3, + DW_RLE_offset_pair = 0x4, + DW_RLE_base_address = 0x5, + DW_RLE_start_end = 0x6, + DW_RLE_start_length = 0x7 + }; + + +/* Location list entry encoding. */ +enum + { + DW_LLE_end_of_list = 0x0, + DW_LLE_base_addressx = 0x1, + DW_LLE_startx_endx = 0x2, + DW_LLE_startx_length = 0x3, + DW_LLE_offset_pair = 0x4, + DW_LLE_default_location = 0x5, + DW_LLE_base_address = 0x6, + DW_LLE_start_end = 0x7, + DW_LLE_start_length = 0x8 + }; + + +/* GNU DebugFission list entry encodings (.debug_loc.dwo). */ +enum + { + DW_LLE_GNU_end_of_list_entry = 0x0, + DW_LLE_GNU_base_address_selection_entry = 0x1, + DW_LLE_GNU_start_end_entry = 0x2, + DW_LLE_GNU_start_length_entry = 0x3 + }; + +/* DWARF5 package file section identifiers. */ +enum + { + DW_SECT_INFO = 1, + /* Reserved = 2, */ + DW_SECT_ABBREV = 3, + DW_SECT_LINE = 4, + DW_SECT_LOCLISTS = 5, + DW_SECT_STR_OFFSETS = 6, + DW_SECT_MACRO = 7, + DW_SECT_RNGLISTS = 8, + }; + + +/* DWARF call frame instruction encodings. */ +enum + { + DW_CFA_advance_loc = 0x40, + DW_CFA_offset = 0x80, + DW_CFA_restore = 0xc0, + DW_CFA_extended = 0, + + DW_CFA_nop = 0x00, + DW_CFA_set_loc = 0x01, + DW_CFA_advance_loc1 = 0x02, + DW_CFA_advance_loc2 = 0x03, + DW_CFA_advance_loc4 = 0x04, + DW_CFA_offset_extended = 0x05, + DW_CFA_restore_extended = 0x06, + DW_CFA_undefined = 0x07, + DW_CFA_same_value = 0x08, + DW_CFA_register = 0x09, + DW_CFA_remember_state = 0x0a, + DW_CFA_restore_state = 0x0b, + DW_CFA_def_cfa = 0x0c, + DW_CFA_def_cfa_register = 0x0d, + DW_CFA_def_cfa_offset = 0x0e, + DW_CFA_def_cfa_expression = 0x0f, + DW_CFA_expression = 0x10, + DW_CFA_offset_extended_sf = 0x11, + DW_CFA_def_cfa_sf = 0x12, + DW_CFA_def_cfa_offset_sf = 0x13, + DW_CFA_val_offset = 0x14, + DW_CFA_val_offset_sf = 0x15, + DW_CFA_val_expression = 0x16, + + DW_CFA_low_user = 0x1c, + DW_CFA_MIPS_advance_loc8 = 0x1d, + DW_CFA_GNU_window_save = 0x2d, + DW_CFA_AARCH64_negate_ra_state = 0x2d, + DW_CFA_GNU_args_size = 0x2e, + DW_CFA_GNU_negative_offset_extended = 0x2f, + DW_CFA_high_user = 0x3f + }; + +/* ID indicating CIE as opposed to FDE in .debug_frame. */ +enum + { + DW_CIE_ID_32 = 0xffffffffU, /* In 32-bit format CIE header. */ + DW_CIE_ID_64 = 0xffffffffffffffffULL /* In 64-bit format CIE header. */ + }; + + +/* Information for GNU unwind information. */ +enum + { + DW_EH_PE_absptr = 0x00, + DW_EH_PE_omit = 0xff, + + /* FDE data encoding. */ + DW_EH_PE_uleb128 = 0x01, + DW_EH_PE_udata2 = 0x02, + DW_EH_PE_udata4 = 0x03, + DW_EH_PE_udata8 = 0x04, + DW_EH_PE_sleb128 = 0x09, + DW_EH_PE_sdata2 = 0x0a, + DW_EH_PE_sdata4 = 0x0b, + DW_EH_PE_sdata8 = 0x0c, + DW_EH_PE_signed = 0x08, + + /* FDE flags. */ + DW_EH_PE_pcrel = 0x10, + DW_EH_PE_textrel = 0x20, + DW_EH_PE_datarel = 0x30, + DW_EH_PE_funcrel = 0x40, + DW_EH_PE_aligned = 0x50, + + DW_EH_PE_indirect = 0x80 + }; + + +/* DWARF XXX. */ +#define DW_ADDR_none 0 + +/* Section 7.2.2 of the DWARF3 specification defines a range of escape + codes that can appear in the length field of certain DWARF structures. + + These defines enumerate the minimum and maximum values of this range. + Currently only the maximum value is used (to indicate that 64-bit + values are going to be used in the dwarf data that accompanies the + structure). The other values are reserved. + + Note: There is a typo in DWARF3 spec (published Dec 20, 2005). In + sections 7.4, 7.5.1, 7.19, 7.20 the minimum escape code is referred to + as 0xffffff00 whereas in fact it should be 0xfffffff0. */ +#define DWARF3_LENGTH_MIN_ESCAPE_CODE 0xfffffff0u +#define DWARF3_LENGTH_MAX_ESCAPE_CODE 0xffffffffu +#define DWARF3_LENGTH_64_BIT DWARF3_LENGTH_MAX_ESCAPE_CODE + +#endif /* dwarf.h */ diff --git a/programs/src/tcc/elf.h b/programs/src/tcc/elf.h new file mode 100644 index 0000000..15645ee --- /dev/null +++ b/programs/src/tcc/elf.h @@ -0,0 +1,3324 @@ +/* This file defines standard ELF types, structures, and macros. + Copyright (C) 1995-2012 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. + + 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 + . */ + +#ifndef _ELF_H +#define _ELF_H 1 + +#ifndef _WIN32 +#include +#else +#ifndef __int8_t_defined +#define __int8_t_defined +typedef signed char int8_t; +typedef short int int16_t; +typedef int int32_t; +typedef long long int int64_t; +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long int uint64_t; +#endif +#endif + +/* Standard ELF types. */ + +/* Type for a 16-bit quantity. */ +typedef uint16_t Elf32_Half; +typedef uint16_t Elf64_Half; + +/* Types for signed and unsigned 32-bit quantities. */ +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; + +/* Types for signed and unsigned 64-bit quantities. */ +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* Type of addresses. */ +typedef uint32_t Elf32_Addr; +typedef uint64_t Elf64_Addr; + +/* Type of file offsets. */ +typedef uint32_t Elf32_Off; +typedef uint64_t Elf64_Off; + +/* Type for section indices, which are 16-bit quantities. */ +typedef uint16_t Elf32_Section; +typedef uint16_t Elf64_Section; + +/* Type for version symbol information. */ +typedef Elf32_Half Elf32_Versym; +typedef Elf64_Half Elf64_Versym; + + +/* The ELF file header. This appears at the start of every ELF file. */ + +#define EI_NIDENT (16) + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Architecture */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point virtual address */ + Elf32_Off e_phoff; /* Program header table file offset */ + Elf32_Off e_shoff; /* Section header table file offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size in bytes */ + Elf32_Half e_phentsize; /* Program header table entry size */ + Elf32_Half e_phnum; /* Program header table entry count */ + Elf32_Half e_shentsize; /* Section header table entry size */ + Elf32_Half e_shnum; /* Section header table entry count */ + Elf32_Half e_shstrndx; /* Section header string table index */ +} Elf32_Ehdr; + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Architecture */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size in bytes */ + Elf64_Half e_phentsize; /* Program header table entry size */ + Elf64_Half e_phnum; /* Program header table entry count */ + Elf64_Half e_shentsize; /* Section header table entry size */ + Elf64_Half e_shnum; /* Section header table entry count */ + Elf64_Half e_shstrndx; /* Section header string table index */ +} Elf64_Ehdr; + +/* Fields in the e_ident array. The EI_* macros are indices into the + array. The macros under each EI_* macro are the values the byte + may have. */ + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7f /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +/* Conglomeration of the identification bytes, for easy testing as a word. */ +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ +#define ELFCLASSNUM 3 + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ +#define ELFDATANUM 3 + +#define EI_VERSION 6 /* File version byte index */ + /* Value must be EV_CURRENT */ + +#define EI_OSABI 7 /* OS ABI identification */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_SYSV 0 /* Alias. */ +#define ELFOSABI_HPUX 1 /* HP-UX */ +#define ELFOSABI_NETBSD 2 /* NetBSD. */ +#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */ +#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */ +#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ +#define ELFOSABI_AIX 7 /* IBM AIX. */ +#define ELFOSABI_IRIX 8 /* SGI Irix. */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ +#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ +#define ELFOSABI_OPENVMS 13 +#define ELFOSABI_NSK 14 /* Hewlett-Packard Non-Stop Kernel. */ +#define ELFOSABI_AROS 15 /* Amiga Research OS. */ +#define ELFOSABI_FENIXOS 16 /* FenixOS. */ +#define ELFOSABI_ARM_AEABI 64 /* ARM EABI. */ +#define ELFOSABI_C6000_LINUX 65 /* Linux TMS320C6000. */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define EI_ABIVERSION 8 /* ABI version */ + +#define EI_PAD 9 /* Byte index of padding bytes */ + +/* Legal values for e_type (object file type). */ + +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_NUM 5 /* Number of defined types */ +#define ET_LOOS 0xfe00 /* OS-specific range start */ +#define ET_HIOS 0xfeff /* OS-specific range end */ +#define ET_LOPROC 0xff00 /* Processor-specific range start */ +#define ET_HIPROC 0xffff /* Processor-specific range end */ + +/* Legal values for e_machine (architecture). */ + +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SUN SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola m68k family */ +#define EM_88K 5 /* Motorola m88k family */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 big-endian */ +#define EM_S370 9 /* IBM System/370 */ +#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ + +#define EM_PARISC 15 /* HPPA */ +#define EM_VPP500 17 /* Fujitsu VPP500 */ +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ +#define EM_960 19 /* Intel 80960 */ +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* PowerPC 64-bit */ +#define EM_S390 22 /* IBM S390 */ + +#define EM_V800 36 /* NEC V800 series */ +#define EM_FR20 37 /* Fujitsu FR20 */ +#define EM_RH32 38 /* TRW RH-32 */ +#define EM_RCE 39 /* Motorola RCE */ +#define EM_ARM 40 /* ARM */ +#define EM_FAKE_ALPHA 41 /* Digital Alpha */ +#define EM_SH 42 /* Hitachi SH */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_TRICORE 44 /* Siemens Tricore */ +#define EM_ARC 45 /* Argonaut RISC Core */ +#define EM_H8_300 46 /* Hitachi H8/300 */ +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ +#define EM_H8_500 49 /* Hitachi H8/500 */ +#define EM_IA_64 50 /* Intel Merced */ +#define EM_MIPS_X 51 /* Stanford MIPS-X */ +#define EM_COLDFIRE 52 /* Motorola Coldfire */ +#define EM_68HC12 53 /* Motorola M68HC12 */ +#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ +#define EM_PCP 55 /* Siemens PCP */ +#define EM_NCPU 56 /* Sony nCPU embedded RISC */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor */ +#define EM_STARCORE 58 /* Motorola Start*Core processor */ +#define EM_ME16 59 /* Toyota ME16 processor */ +#define EM_ST100 60 /* STMicroelectronic ST100 processor */ +#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ +#define EM_X86_64 62 /* AMD x86-64 architecture */ +#define EM_PDSP 63 /* Sony DSP Processor */ + +#define EM_FX66 66 /* Siemens FX66 microcontroller */ +#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ +#define EM_ST7 68 /* STMicroelectronics ST7 8 bit mc */ +#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ +#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ +#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ +#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ +#define EM_SVX 73 /* Silicon Graphics SVx */ +#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ +#define EM_VAX 75 /* Digital VAX */ +#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ +#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ +#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ +#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ +#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ +#define EM_HUANY 81 /* Harvard University machine-independent object files */ +#define EM_PRISM 82 /* SiTera Prism */ +#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ +#define EM_FR30 84 /* Fujitsu FR30 */ +#define EM_D10V 85 /* Mitsubishi D10V */ +#define EM_D30V 86 /* Mitsubishi D30V */ +#define EM_V850 87 /* NEC v850 */ +#define EM_M32R 88 /* Mitsubishi M32R */ +#define EM_MN10300 89 /* Matsushita MN10300 */ +#define EM_MN10200 90 /* Matsushita MN10200 */ +#define EM_PJ 91 /* picoJava */ +#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ +#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ +#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ +#define EM_AARCH64 183 /* ARM AARCH64 */ +#define EM_TILEPRO 188 /* Tilera TILEPro */ +#define EM_TILEGX 191 /* Tilera TILE-Gx */ +#define EM_RISCV 243 /* RISC-V */ +#define EM_NUM 253 + +/* If it is necessary to assign new unofficial EM_* values, please + pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the + chances of collision with official or non-GNU unofficial values. */ + +#define EM_ALPHA 0x9026 +#define EM_C60 0x9c60 + +/* Legal values for e_version (version). */ + +#define EV_NONE 0 /* Invalid ELF version */ +#define EV_CURRENT 1 /* Current version */ +#define EV_NUM 2 + +/* Section header. */ + +typedef struct +{ + Elf32_Word sh_name; /* Section name (string tbl index) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Section virtual addr at execution */ + Elf32_Off sh_offset; /* Section file offset */ + Elf32_Word sh_size; /* Section size in bytes */ + Elf32_Word sh_link; /* Link to another section */ + Elf32_Word sh_info; /* Additional section information */ + Elf32_Word sh_addralign; /* Section alignment */ + Elf32_Word sh_entsize; /* Entry size if section holds table */ +} Elf32_Shdr; + +typedef struct +{ + Elf64_Word sh_name; /* Section name (string tbl index) */ + Elf64_Word sh_type; /* Section type */ + Elf64_Xword sh_flags; /* Section flags */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Section size in bytes */ + Elf64_Word sh_link; /* Link to another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +/* Special section indices. */ + +#define SHN_UNDEF 0 /* Undefined section */ +#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ +#define SHN_LOPROC 0xff00 /* Start of processor-specific */ +#define SHN_BEFORE 0xff00 /* Order section before all others + (Solaris). */ +#define SHN_AFTER 0xff01 /* Order section after all others + (Solaris). */ +#define SHN_HIPROC 0xff1f /* End of processor-specific */ +#define SHN_LOOS 0xff20 /* Start of OS-specific */ +#define SHN_HIOS 0xff3f /* End of OS-specific */ +#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ +#define SHN_COMMON 0xfff2 /* Associated symbol is common */ +#define SHN_XINDEX 0xffff /* Index is in extra table. */ +#define SHN_HIRESERVE 0xffff /* End of reserved indices */ + +/* Legal values for sh_type (section type). */ + +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program data */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Dynamic linking information */ +#define SHT_NOTE 7 /* Notes */ +#define SHT_NOBITS 8 /* Program space with no data (bss) */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved */ +#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ +#define SHT_INIT_ARRAY 14 /* Array of constructors */ +#define SHT_FINI_ARRAY 15 /* Array of destructors */ +#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ +#define SHT_GROUP 17 /* Section group */ +#define SHT_SYMTAB_SHNDX 18 /* Extended section indices */ +#define SHT_NUM 19 /* Number of defined types. */ +#define SHT_LOOS 0x60000000 /* Start OS-specific. */ +#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ +#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ +#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ +#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ +#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ +#define SHT_SUNW_move 0x6ffffffa +#define SHT_SUNW_COMDAT 0x6ffffffb +#define SHT_SUNW_syminfo 0x6ffffffc +#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ +#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ +#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ +#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ +#define SHT_HIOS 0x6fffffff /* End OS-specific type */ +#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ +#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ +#define SHT_LOUSER 0x80000000 /* Start of application-specific */ +#define SHT_HIUSER 0x8fffffff /* End of application-specific */ + +/* Legal values for sh_flags (section flags). */ + +#define SHF_WRITE (1 << 0) /* Writable */ +#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ +#define SHF_EXECINSTR (1 << 2) /* Executable */ +#define SHF_MERGE (1 << 4) /* Might be merged */ +#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ +#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ +#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ +#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling + required */ +#define SHF_GROUP (1 << 9) /* Section is member of a group. */ +#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ +#define SHF_COMPRESSED (1 << 11) /* Section with compressed data. */ +#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ +#define SHF_ORDERED (1 << 30) /* Special ordering requirement + (Solaris). */ +#define SHF_EXCLUDE (1U << 31) /* Section is excluded unless + referenced or allocated (Solaris).*/ + +/* Section group handling. */ +#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ + +/* Symbol table entry. */ + +typedef struct +{ + Elf32_Word st_name; /* Symbol name (string tbl index) */ + Elf32_Addr st_value; /* Symbol value */ + Elf32_Word st_size; /* Symbol size */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf32_Section st_shndx; /* Section index */ +} Elf32_Sym; + +typedef struct +{ + Elf64_Word st_name; /* Symbol name (string tbl index) */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf64_Section st_shndx; /* Section index */ + Elf64_Addr st_value; /* Symbol value */ + Elf64_Xword st_size; /* Symbol size */ +} Elf64_Sym; + +/* The syminfo section if available contains additional information about + every dynamic symbol. */ + +typedef struct +{ + Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf32_Half si_flags; /* Per symbol flags */ +} Elf32_Syminfo; + +typedef struct +{ + Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf64_Half si_flags; /* Per symbol flags */ +} Elf64_Syminfo; + +/* Possible values for si_boundto. */ +#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ +#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ +#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ + +/* Possible bitmasks for si_flags. */ +#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ +#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ +#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ +#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy + loaded */ +/* Syminfo version values. */ +#define SYMINFO_NONE 0 +#define SYMINFO_CURRENT 1 +#define SYMINFO_NUM 2 + + +/* How to extract and insert information held in the st_info field. */ + +#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) +#define ELF32_ST_TYPE(val) ((val) & 0xf) +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ +#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) +#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) +#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) + +/* Legal values for ST_BIND subfield of st_info (symbol binding). */ + +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* Weak symbol */ +#define STB_NUM 3 /* Number of defined types. */ +#define STB_LOOS 10 /* Start of OS-specific */ +#define STB_GNU_UNIQUE 10 /* Unique symbol. */ +#define STB_HIOS 12 /* End of OS-specific */ +#define STB_LOPROC 13 /* Start of processor-specific */ +#define STB_HIPROC 15 /* End of processor-specific */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol's name is file name */ +#define STT_COMMON 5 /* Symbol is a common data object */ +#define STT_TLS 6 /* Symbol is thread-local data object*/ +#define STT_NUM 7 /* Number of defined types. */ +#define STT_LOOS 10 /* Start of OS-specific */ +#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ +#define STT_HIOS 12 /* End of OS-specific */ +#define STT_LOPROC 13 /* Start of processor-specific */ +#define STT_HIPROC 15 /* End of processor-specific */ + + +/* Symbol table indices are found in the hash buckets and chain table + of a symbol hash table section. This special index value indicates + the end of a chain, meaning no further symbols are found in that bucket. */ + +#define STN_UNDEF 0 /* End of a chain. */ + + +/* How to extract and insert information held in the st_other field. */ + +#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) + +/* For ELF64 the definitions are the same. */ +#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) + +/* Symbol visibility specification encoded in the st_other field. */ +#define STV_DEFAULT 0 /* Default symbol visibility rules */ +#define STV_INTERNAL 1 /* Processor specific hidden class */ +#define STV_HIDDEN 2 /* Sym unavailable in other modules */ +#define STV_PROTECTED 3 /* Not preemptible, not exported */ + + +/* Relocation table entry without addend (in section of type SHT_REL). */ + +typedef struct +{ + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ +} Elf32_Rel; + +/* I have seen two different definitions of the Elf64_Rel and + Elf64_Rela structures, so we'll leave them out until Novell (or + whoever) gets their act together. */ +/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ + +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ +} Elf64_Rel; + +/* Relocation table entry with addend (in section of type SHT_RELA). */ + +typedef struct +{ + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ + Elf32_Sword r_addend; /* Addend */ +} Elf32_Rela; + +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ + Elf64_Sxword r_addend; /* Addend */ +} Elf64_Rela; + +/* How to extract and insert information held in the r_info field. */ + +#define ELF32_R_SYM(val) ((val) >> 8) +#define ELF32_R_TYPE(val) ((val) & 0xff) +#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) +#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) + +/* Program segment header. */ + +typedef struct +{ + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +} Elf32_Phdr; + +typedef struct +{ + Elf64_Word p_type; /* Segment type */ + Elf64_Word p_flags; /* Segment flags */ + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment */ +} Elf64_Phdr; + +/* Special value for e_phnum. This indicates that the real number of + program headers is too large to fit into e_phnum. Instead the real + value is in the field sh_info of section 0. */ + +#define PN_XNUM 0xffff + +/* Legal values for p_type (segment type). */ + +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_TLS 7 /* Thread-local storage segment */ +#define PT_NUM 8 /* Number of defined types */ +#define PT_LOOS 0x60000000 /* Start of OS-specific */ +#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ +#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ +#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ +#define PT_LOSUNW 0x6ffffffa +#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ +#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ +#define PT_HISUNW 0x6fffffff +#define PT_HIOS 0x6fffffff /* End of OS-specific */ +#define PT_LOPROC 0x70000000 /* Start of processor-specific */ +#define PT_HIPROC 0x7fffffff /* End of processor-specific */ + +/* Legal values for p_flags (segment flags). */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ +#define PF_MASKOS 0x0ff00000 /* OS-specific */ +#define PF_MASKPROC 0xf0000000 /* Processor-specific */ + +/* Legal values for note segment descriptor types for core files. */ + +#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ +#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ +#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ +#define NT_PRXREG 4 /* Contains copy of prxregset struct */ +#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ +#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ +#define NT_AUXV 6 /* Contains copy of auxv array */ +#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ +#define NT_ASRS 8 /* Contains copy of asrset struct */ +#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ +#define NT_PSINFO 13 /* Contains copy of psinfo struct */ +#define NT_PRCRED 14 /* Contains copy of prcred struct */ +#define NT_UTSNAME 15 /* Contains copy of utsname struct */ +#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ +#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ +#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ +#define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */ +#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ +#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ +#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ +#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ +#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ +#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ +#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */ +#define NT_S390_TIMER 0x301 /* s390 timer register */ +#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */ +#define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */ +#define NT_S390_CTRS 0x304 /* s390 control registers */ +#define NT_S390_PREFIX 0x305 /* s390 prefix register */ +#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ +#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ +#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ +#define NT_ARM_TLS 0x401 /* ARM TLS register */ +#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */ +#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */ + +/* Legal values for the note segment descriptor types for object files. */ + +#define NT_VERSION 1 /* Contains a version string. */ + + +/* Dynamic section entry. */ + +typedef struct +{ + Elf32_Sword d_tag; /* Dynamic entry type */ + union + { + Elf32_Word d_val; /* Integer value */ + Elf32_Addr d_ptr; /* Address value */ + } d_un; +} Elf32_Dyn; + +typedef struct +{ + Elf64_Sxword d_tag; /* Dynamic entry type */ + union + { + Elf64_Xword d_val; /* Integer value */ + Elf64_Addr d_ptr; /* Address value */ + } d_un; +} Elf64_Dyn; + +/* Legal values for d_tag (dynamic entry type). */ + +#define DT_NULL 0 /* Marks end of dynamic section */ +#define DT_NEEDED 1 /* Name of needed library */ +#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ +#define DT_PLTGOT 3 /* Processor defined value */ +#define DT_HASH 4 /* Address of symbol hash table */ +#define DT_STRTAB 5 /* Address of string table */ +#define DT_SYMTAB 6 /* Address of symbol table */ +#define DT_RELA 7 /* Address of Rela relocs */ +#define DT_RELASZ 8 /* Total size of Rela relocs */ +#define DT_RELAENT 9 /* Size of one Rela reloc */ +#define DT_STRSZ 10 /* Size of string table */ +#define DT_SYMENT 11 /* Size of one symbol table entry */ +#define DT_INIT 12 /* Address of init function */ +#define DT_FINI 13 /* Address of termination function */ +#define DT_SONAME 14 /* Name of shared object */ +#define DT_RPATH 15 /* Library search path (deprecated) */ +#define DT_SYMBOLIC 16 /* Start symbol search here */ +#define DT_REL 17 /* Address of Rel relocs */ +#define DT_RELSZ 18 /* Total size of Rel relocs */ +#define DT_RELENT 19 /* Size of one Rel reloc */ +#define DT_PLTREL 20 /* Type of reloc in PLT */ +#define DT_DEBUG 21 /* For debugging; unspecified */ +#define DT_TEXTREL 22 /* Reloc might modify .text */ +#define DT_JMPREL 23 /* Address of PLT relocs */ +#define DT_BIND_NOW 24 /* Process relocations of object */ +#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ +#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ +#define DT_RUNPATH 29 /* Library search path */ +#define DT_FLAGS 30 /* Flags for the object being loaded */ +#define DT_ENCODING 32 /* Start of encoded range */ +#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ +#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ +#define DT_NUM 34 /* Number used */ +#define DT_LOOS 0x6000000d /* Start of OS-specific */ +#define DT_HIOS 0x6ffff000 /* End of OS-specific */ +#define DT_LOPROC 0x70000000 /* Start of processor-specific */ +#define DT_HIPROC 0x7fffffff /* End of processor-specific */ +#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ + +/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the + Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's + approach. */ +#define DT_VALRNGLO 0x6ffffd00 +#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ +#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ +#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ +#define DT_CHECKSUM 0x6ffffdf8 +#define DT_PLTPADSZ 0x6ffffdf9 +#define DT_MOVEENT 0x6ffffdfa +#define DT_MOVESZ 0x6ffffdfb +#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ +#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting + the following DT_* entry. */ +#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ +#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ +#define DT_VALRNGHI 0x6ffffdff +#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ +#define DT_VALNUM 12 + +/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the + Dyn.d_un.d_ptr field of the Elf*_Dyn structure. + + If any adjustment is made to the ELF object after it has been + built these entries will need to be adjusted. */ +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ +#define DT_TLSDESC_PLT 0x6ffffef6 +#define DT_TLSDESC_GOT 0x6ffffef7 +#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ +#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ +#define DT_CONFIG 0x6ffffefa /* Configuration information. */ +#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ +#define DT_AUDIT 0x6ffffefc /* Object auditing. */ +#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ +#define DT_MOVETAB 0x6ffffefe /* Move table. */ +#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ +#define DT_ADDRNUM 11 + +/* The versioning entry types. The next are defined as part of the + GNU extension. */ +#define DT_VERSYM 0x6ffffff0 + +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa + +/* These were chosen by Sun. */ +#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ +#define DT_VERDEF 0x6ffffffc /* Address of version definition + table */ +#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ +#define DT_VERNEED 0x6ffffffe /* Address of table with needed + versions */ +#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ +#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ +#define DT_VERSIONTAGNUM 16 + +/* Sun added these machine-independent extensions in the "processor-specific" + range. Be compatible. */ +#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ +#define DT_FILTER 0x7fffffff /* Shared object to get values from */ +#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) +#define DT_EXTRANUM 3 + +/* Values of `d_un.d_val' in the DT_FLAGS entry. */ +#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ +#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ +#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ +#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ +#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ + +/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 + entry in the dynamic section. */ +#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ +#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ +#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ +#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ +#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ +#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ +#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ +#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ +#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ +#define DF_1_TRANS 0x00000200 +#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ +#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ +#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ +#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ +#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ +#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ +#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ +#define DF_1_NODIRECT 0x00020000 /* Object has no-direct binding. */ +#define DF_1_IGNMULDEF 0x00040000 +#define DF_1_NOKSYMS 0x00080000 +#define DF_1_NOHDR 0x00100000 +#define DF_1_EDITED 0x00200000 /* Object is modified after built. */ +#define DF_1_NORELOC 0x00400000 +#define DF_1_SYMINTPOSE 0x00800000 /* Object has individual interposers. */ +#define DF_1_GLOBAUDIT 0x01000000 /* Global auditing required. */ +#define DF_1_SINGLETON 0x02000000 /* Singleton symbols are used. */ +#define DF_1_PIE 0x08000000 + +/* Flags for the feature selection in DT_FEATURE_1. */ +#define DTF_1_PARINIT 0x00000001 +#define DTF_1_CONFEXP 0x00000002 + +/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ +#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ +#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not + generally available. */ + +/* Version definition sections. */ + +typedef struct +{ + Elf32_Half vd_version; /* Version revision */ + Elf32_Half vd_flags; /* Version information */ + Elf32_Half vd_ndx; /* Version Index */ + Elf32_Half vd_cnt; /* Number of associated aux entries */ + Elf32_Word vd_hash; /* Version name hash value */ + Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf32_Word vd_next; /* Offset in bytes to next verdef + entry */ +} Elf32_Verdef; + +typedef struct +{ + Elf64_Half vd_version; /* Version revision */ + Elf64_Half vd_flags; /* Version information */ + Elf64_Half vd_ndx; /* Version Index */ + Elf64_Half vd_cnt; /* Number of associated aux entries */ + Elf64_Word vd_hash; /* Version name hash value */ + Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf64_Word vd_next; /* Offset in bytes to next verdef + entry */ +} Elf64_Verdef; + + +/* Legal values for vd_version (version revision). */ +#define VER_DEF_NONE 0 /* No version */ +#define VER_DEF_CURRENT 1 /* Current version */ +#define VER_DEF_NUM 2 /* Given version number */ + +/* Legal values for vd_flags (version information flags). */ +#define VER_FLG_BASE 0x1 /* Version definition of file itself */ +#define VER_FLG_WEAK 0x2 /* Weak version identifier */ + +/* Versym symbol index values. */ +#define VER_NDX_LOCAL 0 /* Symbol is local. */ +#define VER_NDX_GLOBAL 1 /* Symbol is global. */ +#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ +#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ + +/* Auxiliary version information. */ + +typedef struct +{ + Elf32_Word vda_name; /* Version or dependency names */ + Elf32_Word vda_next; /* Offset in bytes to next verdaux + entry */ +} Elf32_Verdaux; + +typedef struct +{ + Elf64_Word vda_name; /* Version or dependency names */ + Elf64_Word vda_next; /* Offset in bytes to next verdaux + entry */ +} Elf64_Verdaux; + + +/* Version dependency section. */ + +typedef struct +{ + Elf32_Half vn_version; /* Version of structure */ + Elf32_Half vn_cnt; /* Number of associated aux entries */ + Elf32_Word vn_file; /* Offset of filename for this + dependency */ + Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ + Elf32_Word vn_next; /* Offset in bytes to next verneed + entry */ +} Elf32_Verneed; + +typedef struct +{ + Elf64_Half vn_version; /* Version of structure */ + Elf64_Half vn_cnt; /* Number of associated aux entries */ + Elf64_Word vn_file; /* Offset of filename for this + dependency */ + Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ + Elf64_Word vn_next; /* Offset in bytes to next verneed + entry */ +} Elf64_Verneed; + + +/* Legal values for vn_version (version revision). */ +#define VER_NEED_NONE 0 /* No version */ +#define VER_NEED_CURRENT 1 /* Current version */ +#define VER_NEED_NUM 2 /* Given version number */ + +/* Auxiliary needed version information. */ + +typedef struct +{ + Elf32_Word vna_hash; /* Hash value of dependency name */ + Elf32_Half vna_flags; /* Dependency specific information */ + Elf32_Half vna_other; /* Unused */ + Elf32_Word vna_name; /* Dependency name string offset */ + Elf32_Word vna_next; /* Offset in bytes to next vernaux + entry */ +} Elf32_Vernaux; + +typedef struct +{ + Elf64_Word vna_hash; /* Hash value of dependency name */ + Elf64_Half vna_flags; /* Dependency specific information */ + Elf64_Half vna_other; /* Unused */ + Elf64_Word vna_name; /* Dependency name string offset */ + Elf64_Word vna_next; /* Offset in bytes to next vernaux + entry */ +} Elf64_Vernaux; + + +/* Legal values for vna_flags. */ +#define VER_FLG_WEAK 0x2 /* Weak version identifier */ + + +/* Auxiliary vector. */ + +/* This vector is normally only used by the program interpreter. The + usual definition in an ABI supplement uses the name auxv_t. The + vector is not usually defined in a standard file, but it + can't hurt. We rename it to avoid conflicts. The sizes of these + types are an arrangement between the exec server and the program + interpreter, so we don't fully specify them here. */ + +typedef struct +{ + uint32_t a_type; /* Entry type */ + union + { + uint32_t a_val; /* Integer value */ + /* We use to have pointer elements added here. We cannot do that, + though, since it does not work when using 32-bit definitions + on 64-bit platforms and vice versa. */ + } a_un; +} Elf32_auxv_t; + +typedef struct +{ + uint64_t a_type; /* Entry type */ + union + { + uint64_t a_val; /* Integer value */ + /* We use to have pointer elements added here. We cannot do that, + though, since it does not work when using 32-bit definitions + on 64-bit platforms and vice versa. */ + } a_un; +} Elf64_auxv_t; + +/* Legal values for a_type (entry type). */ + +#define AT_NULL 0 /* End of vector */ +#define AT_IGNORE 1 /* Entry should be ignored */ +#define AT_EXECFD 2 /* File descriptor of program */ +#define AT_PHDR 3 /* Program headers for program */ +#define AT_PHENT 4 /* Size of program header entry */ +#define AT_PHNUM 5 /* Number of program headers */ +#define AT_PAGESZ 6 /* System page size */ +#define AT_BASE 7 /* Base address of interpreter */ +#define AT_FLAGS 8 /* Flags */ +#define AT_ENTRY 9 /* Entry point of program */ +#define AT_NOTELF 10 /* Program is not ELF */ +#define AT_UID 11 /* Real uid */ +#define AT_EUID 12 /* Effective uid */ +#define AT_GID 13 /* Real gid */ +#define AT_EGID 14 /* Effective gid */ +#define AT_CLKTCK 17 /* Frequency of times() */ + +/* Some more special a_type values describing the hardware. */ +#define AT_PLATFORM 15 /* String identifying platform. */ +#define AT_HWCAP 16 /* Machine dependent hints about + processor capabilities. */ + +/* This entry gives some information about the FPU initialization + performed by the kernel. */ +#define AT_FPUCW 18 /* Used FPU control word. */ + +/* Cache block sizes. */ +#define AT_DCACHEBSIZE 19 /* Data cache block size. */ +#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ +#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ + +/* A special ignored value for PPC, used by the kernel to control the + interpretation of the AUXV. Must be > 16. */ +#define AT_IGNOREPPC 22 /* Entry should be ignored. */ + +#define AT_SECURE 23 /* Boolean, was exec setuid-like? */ + +#define AT_BASE_PLATFORM 24 /* String identifying real platforms.*/ + +#define AT_RANDOM 25 /* Address of 16 random bytes. */ + +#define AT_EXECFN 31 /* Filename of executable. */ + +/* Pointer to the global system page used for system calls and other + nice things. */ +#define AT_SYSINFO 32 +#define AT_SYSINFO_EHDR 33 + +/* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains + log2 of line size; mask those to get cache size. */ +#define AT_L1I_CACHESHAPE 34 +#define AT_L1D_CACHESHAPE 35 +#define AT_L2_CACHESHAPE 36 +#define AT_L3_CACHESHAPE 37 + +/* Note section contents. Each entry in the note section begins with + a header of a fixed form. */ + +typedef struct +{ + Elf32_Word n_namesz; /* Length of the note's name. */ + Elf32_Word n_descsz; /* Length of the note's descriptor. */ + Elf32_Word n_type; /* Type of the note. */ +} Elf32_Nhdr; + +typedef struct +{ + Elf64_Word n_namesz; /* Length of the note's name. */ + Elf64_Word n_descsz; /* Length of the note's descriptor. */ + Elf64_Word n_type; /* Type of the note. */ +} Elf64_Nhdr; + +/* Known names of notes. */ + +/* Solaris entries in the note section have this name. */ +#define ELF_NOTE_SOLARIS "SUNW Solaris" + +/* Note entries for GNU systems have this name. */ +#define ELF_NOTE_GNU "GNU" + + +/* Defined types of notes for Solaris. */ + +/* Value of descriptor (one word) is desired pagesize for the binary. */ +#define ELF_NOTE_PAGESIZE_HINT 1 + + +/* Defined note types for GNU systems. */ + +/* ABI information. The descriptor consists of words: + word 0: OS descriptor + word 1: major version of the ABI + word 2: minor version of the ABI + word 3: subminor version of the ABI +*/ +#define NT_GNU_ABI_TAG 1 +#define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */ + +/* Known OSes. These values can appear in word 0 of an + NT_GNU_ABI_TAG note section entry. */ +#define ELF_NOTE_OS_LINUX 0 +#define ELF_NOTE_OS_GNU 1 +#define ELF_NOTE_OS_SOLARIS2 2 +#define ELF_NOTE_OS_FREEBSD 3 + +/* Synthetic hwcap information. The descriptor begins with two words: + word 0: number of entries + word 1: bitmask of enabled entries + Then follow variable-length entries, one byte followed by a + '\0'-terminated hwcap name string. The byte gives the bit + number to test if enabled, (1U << bit) & bitmask. */ +#define NT_GNU_HWCAP 2 + +/* Build ID bits as generated by ld --build-id. + The descriptor consists of any nonzero number of bytes. */ +#define NT_GNU_BUILD_ID 3 + +/* Version note generated by GNU gold containing a version string. */ +#define NT_GNU_GOLD_VERSION 4 + + +/* Move records. */ +typedef struct +{ + Elf32_Xword m_value; /* Symbol value. */ + Elf32_Word m_info; /* Size and index. */ + Elf32_Word m_poffset; /* Symbol offset. */ + Elf32_Half m_repeat; /* Repeat count. */ + Elf32_Half m_stride; /* Stride info. */ +} Elf32_Move; + +typedef struct +{ + Elf64_Xword m_value; /* Symbol value. */ + Elf64_Xword m_info; /* Size and index. */ + Elf64_Xword m_poffset; /* Symbol offset. */ + Elf64_Half m_repeat; /* Repeat count. */ + Elf64_Half m_stride; /* Stride info. */ +} Elf64_Move; + +/* Macro to construct move records. */ +#define ELF32_M_SYM(info) ((info) >> 8) +#define ELF32_M_SIZE(info) ((unsigned char) (info)) +#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) + +#define ELF64_M_SYM(info) ELF32_M_SYM (info) +#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) +#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) + + +/* Motorola 68k specific definitions. */ + +/* Values for Elf32_Ehdr.e_flags. */ +#define EF_CPU32 0x00810000 + +/* m68k relocs. */ + +#define R_68K_NONE 0 /* No reloc */ +#define R_68K_32 1 /* Direct 32 bit */ +#define R_68K_16 2 /* Direct 16 bit */ +#define R_68K_8 3 /* Direct 8 bit */ +#define R_68K_PC32 4 /* PC relative 32 bit */ +#define R_68K_PC16 5 /* PC relative 16 bit */ +#define R_68K_PC8 6 /* PC relative 8 bit */ +#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ +#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ +#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ +#define R_68K_GOT32O 10 /* 32 bit GOT offset */ +#define R_68K_GOT16O 11 /* 16 bit GOT offset */ +#define R_68K_GOT8O 12 /* 8 bit GOT offset */ +#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ +#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ +#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ +#define R_68K_PLT32O 16 /* 32 bit PLT offset */ +#define R_68K_PLT16O 17 /* 16 bit PLT offset */ +#define R_68K_PLT8O 18 /* 8 bit PLT offset */ +#define R_68K_COPY 19 /* Copy symbol at runtime */ +#define R_68K_GLOB_DAT 20 /* Create GOT entry */ +#define R_68K_JMP_SLOT 21 /* Create PLT entry */ +#define R_68K_RELATIVE 22 /* Adjust by program base */ +#define R_68K_TLS_GD32 25 /* 32 bit GOT offset for GD */ +#define R_68K_TLS_GD16 26 /* 16 bit GOT offset for GD */ +#define R_68K_TLS_GD8 27 /* 8 bit GOT offset for GD */ +#define R_68K_TLS_LDM32 28 /* 32 bit GOT offset for LDM */ +#define R_68K_TLS_LDM16 29 /* 16 bit GOT offset for LDM */ +#define R_68K_TLS_LDM8 30 /* 8 bit GOT offset for LDM */ +#define R_68K_TLS_LDO32 31 /* 32 bit module-relative offset */ +#define R_68K_TLS_LDO16 32 /* 16 bit module-relative offset */ +#define R_68K_TLS_LDO8 33 /* 8 bit module-relative offset */ +#define R_68K_TLS_IE32 34 /* 32 bit GOT offset for IE */ +#define R_68K_TLS_IE16 35 /* 16 bit GOT offset for IE */ +#define R_68K_TLS_IE8 36 /* 8 bit GOT offset for IE */ +#define R_68K_TLS_LE32 37 /* 32 bit offset relative to + static TLS block */ +#define R_68K_TLS_LE16 38 /* 16 bit offset relative to + static TLS block */ +#define R_68K_TLS_LE8 39 /* 8 bit offset relative to + static TLS block */ +#define R_68K_TLS_DTPMOD32 40 /* 32 bit module number */ +#define R_68K_TLS_DTPREL32 41 /* 32 bit module-relative offset */ +#define R_68K_TLS_TPREL32 42 /* 32 bit TP-relative offset */ +/* Keep this the last entry. */ +#define R_68K_NUM 43 + +/* Intel 80386 specific definitions. */ + +/* i386 relocs. */ + +#define R_386_NONE 0 /* No reloc */ +#define R_386_32 1 /* Direct 32 bit */ +#define R_386_PC32 2 /* PC relative 32 bit */ +#define R_386_GOT32 3 /* 32 bit GOT entry */ +#define R_386_PLT32 4 /* 32 bit PLT address */ +#define R_386_COPY 5 /* Copy symbol at runtime */ +#define R_386_GLOB_DAT 6 /* Create GOT entry */ +#define R_386_JMP_SLOT 7 /* Create PLT entry */ +#define R_386_RELATIVE 8 /* Adjust by program base */ +#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ +#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ +#define R_386_32PLT 11 +#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ +#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS + block offset */ +#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block + offset */ +#define R_386_TLS_LE 17 /* Offset relative to static TLS + block */ +#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of + general dynamic thread local data */ +#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of + local dynamic thread local data + in LE code */ +#define R_386_16 20 +#define R_386_PC16 21 +#define R_386_8 22 +#define R_386_PC8 23 +#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic + thread local data */ +#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ +#define R_386_TLS_GD_CALL 26 /* Relocation for call to + __tls_get_addr() */ +#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ +#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic + thread local data in LE code */ +#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ +#define R_386_TLS_LDM_CALL 30 /* Relocation for call to + __tls_get_addr() in LDM code */ +#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ +#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ +#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS + block offset */ +#define R_386_TLS_LE_32 34 /* Negated offset relative to static + TLS block */ +#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ +#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ +#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ +/* 38? */ +#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */ +#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS + descriptor for + relaxation. */ +#define R_386_TLS_DESC 41 /* TLS descriptor containing + pointer to code and to + argument, returning the TLS + offset for the symbol. */ +#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */ +#define R_386_GOT32X 43 /* 32 bit GOT entry, relaxable */ +/* Keep this the last entry. */ +#define R_386_NUM 44 + +/* SUN SPARC specific definitions. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */ + +/* Values for Elf64_Ehdr.e_flags. */ + +#define EF_SPARCV9_MM 3 +#define EF_SPARCV9_TSO 0 +#define EF_SPARCV9_PSO 1 +#define EF_SPARCV9_RMO 2 +#define EF_SPARC_LEDATA 0x800000 /* little endian data */ +#define EF_SPARC_EXT_MASK 0xFFFF00 +#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ +#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ +#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ +#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ + +/* SPARC relocs. */ + +#define R_SPARC_NONE 0 /* No reloc */ +#define R_SPARC_8 1 /* Direct 8 bit */ +#define R_SPARC_16 2 /* Direct 16 bit */ +#define R_SPARC_32 3 /* Direct 32 bit */ +#define R_SPARC_DISP8 4 /* PC relative 8 bit */ +#define R_SPARC_DISP16 5 /* PC relative 16 bit */ +#define R_SPARC_DISP32 6 /* PC relative 32 bit */ +#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ +#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ +#define R_SPARC_HI22 9 /* High 22 bit */ +#define R_SPARC_22 10 /* Direct 22 bit */ +#define R_SPARC_13 11 /* Direct 13 bit */ +#define R_SPARC_LO10 12 /* Truncated 10 bit */ +#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ +#define R_SPARC_GOT13 14 /* 13 bit GOT entry */ +#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ +#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ +#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ +#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ +#define R_SPARC_COPY 19 /* Copy symbol at runtime */ +#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ +#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ +#define R_SPARC_RELATIVE 22 /* Adjust by program base */ +#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ + +/* Additional Sparc64 relocs. */ + +#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ +#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ +#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ +#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ +#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ +#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ +#define R_SPARC_10 30 /* Direct 10 bit */ +#define R_SPARC_11 31 /* Direct 11 bit */ +#define R_SPARC_64 32 /* Direct 64 bit */ +#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ +#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ +#define R_SPARC_HM10 35 /* High middle 10 bits of ... */ +#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ +#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ +#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ +#define R_SPARC_PC_LM22 39 /* Low middle 22 bits of ... */ +#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ +#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ +#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */ +#define R_SPARC_7 43 /* Direct 7 bit */ +#define R_SPARC_5 44 /* Direct 5 bit */ +#define R_SPARC_6 45 /* Direct 6 bit */ +#define R_SPARC_DISP64 46 /* PC relative 64 bit */ +#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ +#define R_SPARC_HIX22 48 /* High 22 bit complemented */ +#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ +#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ +#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ +#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ +#define R_SPARC_REGISTER 53 /* Global register usage */ +#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ +#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ +#define R_SPARC_TLS_GD_HI22 56 +#define R_SPARC_TLS_GD_LO10 57 +#define R_SPARC_TLS_GD_ADD 58 +#define R_SPARC_TLS_GD_CALL 59 +#define R_SPARC_TLS_LDM_HI22 60 +#define R_SPARC_TLS_LDM_LO10 61 +#define R_SPARC_TLS_LDM_ADD 62 +#define R_SPARC_TLS_LDM_CALL 63 +#define R_SPARC_TLS_LDO_HIX22 64 +#define R_SPARC_TLS_LDO_LOX10 65 +#define R_SPARC_TLS_LDO_ADD 66 +#define R_SPARC_TLS_IE_HI22 67 +#define R_SPARC_TLS_IE_LO10 68 +#define R_SPARC_TLS_IE_LD 69 +#define R_SPARC_TLS_IE_LDX 70 +#define R_SPARC_TLS_IE_ADD 71 +#define R_SPARC_TLS_LE_HIX22 72 +#define R_SPARC_TLS_LE_LOX10 73 +#define R_SPARC_TLS_DTPMOD32 74 +#define R_SPARC_TLS_DTPMOD64 75 +#define R_SPARC_TLS_DTPOFF32 76 +#define R_SPARC_TLS_DTPOFF64 77 +#define R_SPARC_TLS_TPOFF32 78 +#define R_SPARC_TLS_TPOFF64 79 +#define R_SPARC_GOTDATA_HIX22 80 +#define R_SPARC_GOTDATA_LOX10 81 +#define R_SPARC_GOTDATA_OP_HIX22 82 +#define R_SPARC_GOTDATA_OP_LOX10 83 +#define R_SPARC_GOTDATA_OP 84 +#define R_SPARC_H34 85 +#define R_SPARC_SIZE32 86 +#define R_SPARC_SIZE64 87 +#define R_SPARC_WDISP10 88 +#define R_SPARC_JMP_IREL 248 +#define R_SPARC_IRELATIVE 249 +#define R_SPARC_GNU_VTINHERIT 250 +#define R_SPARC_GNU_VTENTRY 251 +#define R_SPARC_REV32 252 +/* Keep this the last entry. */ +#define R_SPARC_NUM 253 + +/* For Sparc64, legal values for d_tag of Elf64_Dyn. */ + +#define DT_SPARC_REGISTER 0x70000001 +#define DT_SPARC_NUM 2 + +/* MIPS R3000 specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ +#define EF_MIPS_PIC 2 /* Contains PIC code */ +#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ +#define EF_MIPS_XGOT 8 +#define EF_MIPS_64BIT_WHIRL 16 +#define EF_MIPS_ABI2 32 +#define EF_MIPS_ABI_ON32 64 +#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ + +/* Legal values for MIPS architecture level. */ + +#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ +#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ + +/* The following are non-official names and should not be used. */ + +#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ +#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ + +/* Special section indices. */ + +#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ +#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ +#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ +#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ +#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ +#define SHT_MIPS_MSYM 0x70000001 +#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ +#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ +#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ +#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ +#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ +#define SHT_MIPS_PACKAGE 0x70000007 +#define SHT_MIPS_PACKSYM 0x70000008 +#define SHT_MIPS_RELD 0x70000009 +#define SHT_MIPS_IFACE 0x7000000b +#define SHT_MIPS_CONTENT 0x7000000c +#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ +#define SHT_MIPS_SHDR 0x70000010 +#define SHT_MIPS_FDESC 0x70000011 +#define SHT_MIPS_EXTSYM 0x70000012 +#define SHT_MIPS_DENSE 0x70000013 +#define SHT_MIPS_PDESC 0x70000014 +#define SHT_MIPS_LOCSYM 0x70000015 +#define SHT_MIPS_AUXSYM 0x70000016 +#define SHT_MIPS_OPTSYM 0x70000017 +#define SHT_MIPS_LOCSTR 0x70000018 +#define SHT_MIPS_LINE 0x70000019 +#define SHT_MIPS_RFDESC 0x7000001a +#define SHT_MIPS_DELTASYM 0x7000001b +#define SHT_MIPS_DELTAINST 0x7000001c +#define SHT_MIPS_DELTACLASS 0x7000001d +#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ +#define SHT_MIPS_DELTADECL 0x7000001f +#define SHT_MIPS_SYMBOL_LIB 0x70000020 +#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ +#define SHT_MIPS_TRANSLATE 0x70000022 +#define SHT_MIPS_PIXIE 0x70000023 +#define SHT_MIPS_XLATE 0x70000024 +#define SHT_MIPS_XLATE_DEBUG 0x70000025 +#define SHT_MIPS_WHIRL 0x70000026 +#define SHT_MIPS_EH_REGION 0x70000027 +#define SHT_MIPS_XLATE_OLD 0x70000028 +#define SHT_MIPS_PDR_EXCEPTION 0x70000029 + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ +#define SHF_MIPS_MERGE 0x20000000 +#define SHF_MIPS_ADDR 0x40000000 +#define SHF_MIPS_STRINGS 0x80000000 +#define SHF_MIPS_NOSTRIP 0x08000000 +#define SHF_MIPS_LOCAL 0x04000000 +#define SHF_MIPS_NAMES 0x02000000 +#define SHF_MIPS_NODUPE 0x01000000 + + +/* Symbol tables. */ + +/* MIPS specific values for `st_other'. */ +#define STO_MIPS_DEFAULT 0x0 +#define STO_MIPS_INTERNAL 0x1 +#define STO_MIPS_HIDDEN 0x2 +#define STO_MIPS_PROTECTED 0x3 +#define STO_MIPS_PLT 0x8 +#define STO_MIPS_SC_ALIGN_UNUSED 0xff + +/* MIPS specific values for `st_info'. */ +#define STB_MIPS_SPLIT_COMMON 13 + +/* Entries found in sections of type SHT_MIPS_GPTAB. */ + +typedef union +{ + struct + { + Elf32_Word gt_current_g_value; /* -G value used for compilation */ + Elf32_Word gt_unused; /* Not used */ + } gt_header; /* First entry in section */ + struct + { + Elf32_Word gt_g_value; /* If this value were used for -G */ + Elf32_Word gt_bytes; /* This many bytes would be used */ + } gt_entry; /* Subsequent entries in section */ +} Elf32_gptab; + +/* Entry found in sections of type SHT_MIPS_REGINFO. */ + +typedef struct +{ + Elf32_Word ri_gprmask; /* General registers used */ + Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ + Elf32_Sword ri_gp_value; /* $gp register value */ +} Elf32_RegInfo; + +/* Entries found in sections of type SHT_MIPS_OPTIONS. */ + +typedef struct +{ + unsigned char kind; /* Determines interpretation of the + variable part of descriptor. */ + unsigned char size; /* Size of descriptor, including header. */ + Elf32_Section section; /* Section header index of section affected, + 0 for global options. */ + Elf32_Word info; /* Kind-specific information. */ +} Elf_Options; + +/* Values for `kind' field in Elf_Options. */ + +#define ODK_NULL 0 /* Undefined. */ +#define ODK_REGINFO 1 /* Register usage information. */ +#define ODK_EXCEPTIONS 2 /* Exception processing options. */ +#define ODK_PAD 3 /* Section padding options. */ +#define ODK_HWPATCH 4 /* Hardware workarounds performed */ +#define ODK_FILL 5 /* record the fill value used by the linker. */ +#define ODK_TAGS 6 /* reserve space for desktop tools to write. */ +#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ +#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ + +/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ + +#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ +#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ +#define OEX_PAGE0 0x10000 /* page zero must be mapped. */ +#define OEX_SMM 0x20000 /* Force sequential memory mode? */ +#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ +#define OEX_PRECISEFP OEX_FPDBUG +#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ + +#define OEX_FPU_INVAL 0x10 +#define OEX_FPU_DIV0 0x08 +#define OEX_FPU_OFLO 0x04 +#define OEX_FPU_UFLO 0x02 +#define OEX_FPU_INEX 0x01 + +/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ + +#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ +#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ +#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ +#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ + +#define OPAD_PREFIX 0x1 +#define OPAD_POSTFIX 0x2 +#define OPAD_SYMBOL 0x4 + +/* Entry found in `.options' section. */ + +typedef struct +{ + Elf32_Word hwp_flags1; /* Extra flags. */ + Elf32_Word hwp_flags2; /* Extra flags. */ +} Elf_Options_Hw; + +/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ + +#define OHWA0_R4KEOP_CHECKED 0x00000001 +#define OHWA1_R4KEOP_CLEAN 0x00000002 + +/* MIPS relocs. */ + +#define R_MIPS_NONE 0 /* No reloc */ +#define R_MIPS_16 1 /* Direct 16 bit */ +#define R_MIPS_32 2 /* Direct 32 bit */ +#define R_MIPS_REL32 3 /* PC relative 32 bit */ +#define R_MIPS_26 4 /* Direct 26 bit shifted */ +#define R_MIPS_HI16 5 /* High 16 bit */ +#define R_MIPS_LO16 6 /* Low 16 bit */ +#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ +#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ +#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ +#define R_MIPS_PC16 10 /* PC relative 16 bit */ +#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ +#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ + +#define R_MIPS_SHIFT5 16 +#define R_MIPS_SHIFT6 17 +#define R_MIPS_64 18 +#define R_MIPS_GOT_DISP 19 +#define R_MIPS_GOT_PAGE 20 +#define R_MIPS_GOT_OFST 21 +#define R_MIPS_GOT_HI16 22 +#define R_MIPS_GOT_LO16 23 +#define R_MIPS_SUB 24 +#define R_MIPS_INSERT_A 25 +#define R_MIPS_INSERT_B 26 +#define R_MIPS_DELETE 27 +#define R_MIPS_HIGHER 28 +#define R_MIPS_HIGHEST 29 +#define R_MIPS_CALL_HI16 30 +#define R_MIPS_CALL_LO16 31 +#define R_MIPS_SCN_DISP 32 +#define R_MIPS_REL16 33 +#define R_MIPS_ADD_IMMEDIATE 34 +#define R_MIPS_PJUMP 35 +#define R_MIPS_RELGOT 36 +#define R_MIPS_JALR 37 +#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ +#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ +#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ +#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ +#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ +#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ +#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ +#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ +#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ +#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ +#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ +#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ +#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ +#define R_MIPS_GLOB_DAT 51 +#define R_MIPS_COPY 126 +#define R_MIPS_JUMP_SLOT 127 +/* Keep this the last entry. */ +#define R_MIPS_NUM 128 + +/* Legal values for p_type field of Elf32_Phdr. */ + +#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ +#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ +#define PT_MIPS_OPTIONS 0x70000002 + +/* Special program header types. */ + +#define PF_MIPS_LOCAL 0x10000000 + +/* Legal values for d_tag field of Elf32_Dyn. */ + +#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ +#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ +#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ +#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ +#define DT_MIPS_FLAGS 0x70000005 /* Flags */ +#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ +#define DT_MIPS_MSYM 0x70000007 +#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ +#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ +#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ +#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ +#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ +#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ +#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ +#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ +#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ +#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ +#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ +#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in + DT_MIPS_DELTA_CLASS. */ +#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ +#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in + DT_MIPS_DELTA_INSTANCE. */ +#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ +#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in + DT_MIPS_DELTA_RELOC. */ +#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta + relocations refer to. */ +#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in + DT_MIPS_DELTA_SYM. */ +#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the + class declaration. */ +#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in + DT_MIPS_DELTA_CLASSSYM. */ +#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ +#define DT_MIPS_PIXIE_INIT 0x70000023 +#define DT_MIPS_SYMBOL_LIB 0x70000024 +#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 +#define DT_MIPS_LOCAL_GOTIDX 0x70000026 +#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 +#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 +#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ +#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ +#define DT_MIPS_DYNSTR_ALIGN 0x7000002b +#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ +#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve + function stored in GOT. */ +#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added + by rld on dlopen() calls. */ +#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ +#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ +#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ +/* The address of .got.plt in an executable using the new non-PIC ABI. */ +#define DT_MIPS_PLTGOT 0x70000032 +/* The base of the PLT in an executable using the new non-PIC ABI if that + PLT is writable. For a non-writable PLT, this is omitted or has a zero + value. */ +#define DT_MIPS_RWPLT 0x70000034 +#define DT_MIPS_NUM 0x35 + +/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ + +#define RHF_NONE 0 /* No flags */ +#define RHF_QUICKSTART (1 << 0) /* Use quickstart */ +#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ +#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ +#define RHF_NO_MOVE (1 << 3) +#define RHF_SGI_ONLY (1 << 4) +#define RHF_GUARANTEE_INIT (1 << 5) +#define RHF_DELTA_C_PLUS_PLUS (1 << 6) +#define RHF_GUARANTEE_START_INIT (1 << 7) +#define RHF_PIXIE (1 << 8) +#define RHF_DEFAULT_DELAY_LOAD (1 << 9) +#define RHF_REQUICKSTART (1 << 10) +#define RHF_REQUICKSTARTED (1 << 11) +#define RHF_CORD (1 << 12) +#define RHF_NO_UNRES_UNDEF (1 << 13) +#define RHF_RLD_ORDER_SAFE (1 << 14) + +/* Entries found in sections of type SHT_MIPS_LIBLIST. */ + +typedef struct +{ + Elf32_Word l_name; /* Name (string table index) */ + Elf32_Word l_time_stamp; /* Timestamp */ + Elf32_Word l_checksum; /* Checksum */ + Elf32_Word l_version; /* Interface version */ + Elf32_Word l_flags; /* Flags */ +} Elf32_Lib; + +typedef struct +{ + Elf64_Word l_name; /* Name (string table index) */ + Elf64_Word l_time_stamp; /* Timestamp */ + Elf64_Word l_checksum; /* Checksum */ + Elf64_Word l_version; /* Interface version */ + Elf64_Word l_flags; /* Flags */ +} Elf64_Lib; + + +/* Legal values for l_flags. */ + +#define LL_NONE 0 +#define LL_EXACT_MATCH (1 << 0) /* Require exact match */ +#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ +#define LL_REQUIRE_MINOR (1 << 2) +#define LL_EXPORTS (1 << 3) +#define LL_DELAY_LOAD (1 << 4) +#define LL_DELTA (1 << 5) + +/* Entries found in sections of type SHT_MIPS_CONFLICT. */ + +typedef Elf32_Addr Elf32_Conflict; + + +/* HPPA specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ +#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ +#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ +#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ +#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch + prediction. */ +#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ +#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ + +/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ + +#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ +#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ +#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ + +/* Additional section indices. */ + +#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tentatively declared + symbols in ANSI C. */ +#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ +#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ +#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ +#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ +#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ + +#define STT_HP_OPAQUE (STT_LOOS + 0x1) +#define STT_HP_STUB (STT_LOOS + 0x2) + +/* HPPA relocs. */ + +#define R_PARISC_NONE 0 /* No reloc. */ +#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ +#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ +#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ +#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ +#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ +#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ +#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ +#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ +#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ +#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ +#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ +#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ +#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ +#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ +#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ +#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ +#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ +#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ +#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ +#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ +#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ +#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ +#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ +#define R_PARISC_FPTR64 64 /* 64 bits function address. */ +#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ +#define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */ +#define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */ +#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ +#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ +#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ +#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ +#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ +#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ +#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ +#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ +#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ +#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ +#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ +#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ +#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ +#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ +#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ +#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ +#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ +#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ +#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LORESERVE 128 +#define R_PARISC_COPY 128 /* Copy relocation. */ +#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ +#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ +#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ +#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ +#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ +#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ +#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ +#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ +#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_GNU_VTENTRY 232 +#define R_PARISC_GNU_VTINHERIT 233 +#define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */ +#define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */ +#define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */ +#define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */ +#define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */ +#define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */ +#define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */ +#define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */ +#define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */ +#define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */ +#define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */ +#define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */ +#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L +#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R +#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L +#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R +#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32 +#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64 +#define R_PARISC_HIRESERVE 255 + +/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ + +#define PT_HP_TLS (PT_LOOS + 0x0) +#define PT_HP_CORE_NONE (PT_LOOS + 0x1) +#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) +#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) +#define PT_HP_CORE_COMM (PT_LOOS + 0x4) +#define PT_HP_CORE_PROC (PT_LOOS + 0x5) +#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) +#define PT_HP_CORE_STACK (PT_LOOS + 0x7) +#define PT_HP_CORE_SHM (PT_LOOS + 0x8) +#define PT_HP_CORE_MMF (PT_LOOS + 0x9) +#define PT_HP_PARALLEL (PT_LOOS + 0x10) +#define PT_HP_FASTBIND (PT_LOOS + 0x11) +#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) +#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) +#define PT_HP_STACK (PT_LOOS + 0x14) + +#define PT_PARISC_ARCHEXT 0x70000000 +#define PT_PARISC_UNWIND 0x70000001 + +/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ + +#define PF_PARISC_SBP 0x08000000 + +#define PF_HP_PAGE_SIZE 0x00100000 +#define PF_HP_FAR_SHARED 0x00200000 +#define PF_HP_NEAR_SHARED 0x00400000 +#define PF_HP_CODE 0x01000000 +#define PF_HP_MODIFY 0x02000000 +#define PF_HP_LAZYSWAP 0x04000000 +#define PF_HP_SBP 0x08000000 + + +/* Alpha specific definitions. */ + +/* Legal values for e_flags field of Elf64_Ehdr. */ + +#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ +#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ + +/* Legal values for sh_type field of Elf64_Shdr. */ + +/* These two are primarily concerned with ECOFF debugging info. */ +#define SHT_ALPHA_DEBUG 0x70000001 +#define SHT_ALPHA_REGINFO 0x70000002 + +/* Legal values for sh_flags field of Elf64_Shdr. */ + +#define SHF_ALPHA_GPREL 0x10000000 + +/* Legal values for st_other field of Elf64_Sym. */ +#define STO_ALPHA_NOPV 0x80 /* No PV required. */ +#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ + +/* Alpha relocs. */ + +#define R_ALPHA_NONE 0 /* No reloc */ +#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ +#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ +#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ +#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ +#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ +#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ +#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ +#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ +#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ +#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ +#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ +#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ +#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ +#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ +#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ +#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ +#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ +#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ +#define R_ALPHA_TLS_GD_HI 28 +#define R_ALPHA_TLSGD 29 +#define R_ALPHA_TLS_LDM 30 +#define R_ALPHA_DTPMOD64 31 +#define R_ALPHA_GOTDTPREL 32 +#define R_ALPHA_DTPREL64 33 +#define R_ALPHA_DTPRELHI 34 +#define R_ALPHA_DTPRELLO 35 +#define R_ALPHA_DTPREL16 36 +#define R_ALPHA_GOTTPREL 37 +#define R_ALPHA_TPREL64 38 +#define R_ALPHA_TPRELHI 39 +#define R_ALPHA_TPRELLO 40 +#define R_ALPHA_TPREL16 41 +/* Keep this the last entry. */ +#define R_ALPHA_NUM 46 + +/* Magic values of the LITUSE relocation addend. */ +#define LITUSE_ALPHA_ADDR 0 +#define LITUSE_ALPHA_BASE 1 +#define LITUSE_ALPHA_BYTOFF 2 +#define LITUSE_ALPHA_JSR 3 +#define LITUSE_ALPHA_TLS_GD 4 +#define LITUSE_ALPHA_TLS_LDM 5 + +/* Legal values for d_tag of Elf64_Dyn. */ +#define DT_ALPHA_PLTRO (DT_LOPROC + 0) +#define DT_ALPHA_NUM 1 + +/* PowerPC specific declarations */ + +/* Values for Elf32/64_Ehdr.e_flags. */ +#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ + +/* Cygnus local bits below */ +#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ +#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib + flag */ + +/* PowerPC relocations defined by the ABIs */ +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 /* 32bit absolute address */ +#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ +#define R_PPC_ADDR16 3 /* 16bit absolute address */ +#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ +#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ +#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ +#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 /* PC relative 26 bit */ +#define R_PPC_REL14 11 /* PC relative 16 bit */ +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 + +/* PowerPC relocations defined for the TLS access ABI. */ +#define R_PPC_TLS 67 /* none (sym+add)@tls */ +#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ +#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ +#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ +#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ +#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ +#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ +#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ +#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ +#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ +#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ +#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ +#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ +#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ +#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ +#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ +#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ +#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ +#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ +#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ +#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ +#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ +#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ +#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ +#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ +#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ +#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ +#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ + +/* The remaining relocs are from the Embedded ELF ABI, and are not + in the SVR4 ELF ABI. */ +#define R_PPC_EMB_NADDR32 101 +#define R_PPC_EMB_NADDR16 102 +#define R_PPC_EMB_NADDR16_LO 103 +#define R_PPC_EMB_NADDR16_HI 104 +#define R_PPC_EMB_NADDR16_HA 105 +#define R_PPC_EMB_SDAI16 106 +#define R_PPC_EMB_SDA2I16 107 +#define R_PPC_EMB_SDA2REL 108 +#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ +#define R_PPC_EMB_MRKREF 110 +#define R_PPC_EMB_RELSEC16 111 +#define R_PPC_EMB_RELST_LO 112 +#define R_PPC_EMB_RELST_HI 113 +#define R_PPC_EMB_RELST_HA 114 +#define R_PPC_EMB_BIT_FLD 115 +#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ + +/* Diab tool relocations. */ +#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ +#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ +#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ +#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ +#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ +#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ + +/* GNU extension to support local ifunc. */ +#define R_PPC_IRELATIVE 248 + +/* GNU relocs used in PIC code sequences. */ +#define R_PPC_REL16 249 /* half16 (sym+add-.) */ +#define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */ +#define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */ +#define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */ + +/* This is a phony reloc to handle any old fashioned TOC16 references + that may still be in object files. */ +#define R_PPC_TOC16 255 + +/* PowerPC specific values for the Dyn d_tag field. */ +#define DT_PPC_GOT (DT_LOPROC + 0) +#define DT_PPC_NUM 1 + +/* PowerPC64 relocations defined by the ABIs */ +#define R_PPC64_NONE R_PPC_NONE +#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ +#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ +#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ +#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ +#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ +#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ +#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ +#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN +#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN +#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ +#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ +#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN +#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN +#define R_PPC64_GOT16 R_PPC_GOT16 +#define R_PPC64_GOT16_LO R_PPC_GOT16_LO +#define R_PPC64_GOT16_HI R_PPC_GOT16_HI +#define R_PPC64_GOT16_HA R_PPC_GOT16_HA + +#define R_PPC64_COPY R_PPC_COPY +#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT +#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT +#define R_PPC64_RELATIVE R_PPC_RELATIVE + +#define R_PPC64_UADDR32 R_PPC_UADDR32 +#define R_PPC64_UADDR16 R_PPC_UADDR16 +#define R_PPC64_REL32 R_PPC_REL32 +#define R_PPC64_PLT32 R_PPC_PLT32 +#define R_PPC64_PLTREL32 R_PPC_PLTREL32 +#define R_PPC64_PLT16_LO R_PPC_PLT16_LO +#define R_PPC64_PLT16_HI R_PPC_PLT16_HI +#define R_PPC64_PLT16_HA R_PPC_PLT16_HA + +#define R_PPC64_SECTOFF R_PPC_SECTOFF +#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO +#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI +#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA +#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ +#define R_PPC64_ADDR64 38 /* doubleword64 S + A */ +#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ +#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ +#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ +#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ +#define R_PPC64_UADDR64 43 /* doubleword64 S + A */ +#define R_PPC64_REL64 44 /* doubleword64 S + A - P */ +#define R_PPC64_PLT64 45 /* doubleword64 L + A */ +#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ +#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ +#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ +#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ +#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ +#define R_PPC64_TOC 51 /* doubleword64 .TOC */ +#define R_PPC64_PLTGOT16 52 /* half16* M + A */ +#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ +#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ +#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ + +#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ +#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ +#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ +#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ +#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ +#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ +#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ +#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ +#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ +#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ +#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ + +/* PowerPC64 relocations defined for the TLS access ABI. */ +#define R_PPC64_TLS 67 /* none (sym+add)@tls */ +#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ +#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ +#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ +#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ +#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ +#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ +#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ +#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ +#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ +#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ +#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ +#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ +#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ +#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ +#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ +#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ +#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ +#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ +#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ +#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ +#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ +#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ +#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ +#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ +#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ +#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ +#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ +#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ +#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ +#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ +#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ +#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ +#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ +#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ +#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ +#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ +#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ +#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ +#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ + +/* GNU extension to support local ifunc. */ +#define R_PPC64_JMP_IREL 247 +#define R_PPC64_IRELATIVE 248 +#define R_PPC64_REL16 249 /* half16 (sym+add-.) */ +#define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */ +#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */ +#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */ + +/* PowerPC64 specific values for the Dyn d_tag field. */ +#define DT_PPC64_GLINK (DT_LOPROC + 0) +#define DT_PPC64_OPD (DT_LOPROC + 1) +#define DT_PPC64_OPDSZ (DT_LOPROC + 2) +#define DT_PPC64_NUM 3 + + +/* ARM specific declarations */ + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_ARM_RELEXEC 0x01 +#define EF_ARM_HASENTRY 0x02 +#define EF_ARM_INTERWORK 0x04 +#define EF_ARM_APCS_26 0x08 +#define EF_ARM_APCS_FLOAT 0x10 +#define EF_ARM_PIC 0x20 +#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ +#define EF_ARM_NEW_ABI 0x80 +#define EF_ARM_OLD_ABI 0x100 +#define EF_ARM_SOFT_FLOAT 0x200 +#define EF_ARM_VFP_FLOAT 0x400 +#define EF_ARM_MAVERICK_FLOAT 0x800 + +#define EF_ARM_ABI_FLOAT_SOFT 0x200 /* NB conflicts with EF_ARM_SOFT_FLOAT */ +#define EF_ARM_ABI_FLOAT_HARD 0x400 /* NB conflicts with EF_ARM_VFP_FLOAT */ + + +/* Other constants defined in the ARM ELF spec. version B-01. */ +/* NB. These conflict with values defined above. */ +#define EF_ARM_SYMSARESORTED 0x04 +#define EF_ARM_DYNSYMSUSESEGIDX 0x08 +#define EF_ARM_MAPSYMSFIRST 0x10 +#define EF_ARM_EABIMASK 0XFF000000 + +/* Constants defined in AAELF. */ +#define EF_ARM_BE8 0x00800000 +#define EF_ARM_LE8 0x00400000 + +#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) +#define EF_ARM_EABI_UNKNOWN 0x00000000 +#define EF_ARM_EABI_VER1 0x01000000 +#define EF_ARM_EABI_VER2 0x02000000 +#define EF_ARM_EABI_VER3 0x03000000 +#define EF_ARM_EABI_VER4 0x04000000 +#define EF_ARM_EABI_VER5 0x05000000 + +/* Additional symbol types for Thumb. */ +#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */ +#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */ + +/* ARM-specific values for sh_flags */ +#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ +#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined + in the input to a link step. */ + +/* ARM-specific program header flags */ +#define PF_ARM_SB 0x10000000 /* Segment contains the location + addressed by the static base. */ +#define PF_ARM_PI 0x20000000 /* Position-independent segment. */ +#define PF_ARM_ABS 0x40000000 /* Absolute segment. */ + +/* Processor specific values for the Phdr p_type field. */ +#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */ + +/* Processor specific values for the Shdr sh_type field. */ +#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */ +#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */ +#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */ + + +/* AArch64 relocs. */ + +#define R_AARCH64_NONE 0 /* No relocation. */ +#define R_AARCH64_ABS64 257 /* Direct 64 bit. */ +#define R_AARCH64_ABS32 258 /* Direct 32 bit. */ +#define R_AARCH64_ABS16 259 /* Direct 16-bit. */ +#define R_AARCH64_PREL64 260 /* PC-relative 64-bit. */ +#define R_AARCH64_PREL32 261 /* PC-relative 32-bit. */ +#define R_AARCH64_PREL16 262 /* PC-relative 16-bit. */ +#define R_AARCH64_MOVW_UABS_G0 263 /* Dir. MOVZ imm. from bits 15:0. */ +#define R_AARCH64_MOVW_UABS_G0_NC 264 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_UABS_G1 265 /* Dir. MOVZ imm. from bits 31:16. */ +#define R_AARCH64_MOVW_UABS_G1_NC 266 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_UABS_G2 267 /* Dir. MOVZ imm. from bits 47:32. */ +#define R_AARCH64_MOVW_UABS_G2_NC 268 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_UABS_G3 269 /* Dir. MOV{K,Z} imm. from 63:48. */ +#define R_AARCH64_MOVW_SABS_G0 270 /* Dir. MOV{N,Z} imm. from 15:0. */ +#define R_AARCH64_MOVW_SABS_G1 271 /* Dir. MOV{N,Z} imm. from 31:16. */ +#define R_AARCH64_MOVW_SABS_G2 272 /* Dir. MOV{N,Z} imm. from 47:32. */ +#define R_AARCH64_LD_PREL_LO19 273 /* PC-rel. LD imm. from bits 20:2. */ +#define R_AARCH64_ADR_PREL_LO21 274 /* PC-rel. ADR imm. from bits 20:0. */ +#define R_AARCH64_ADR_PREL_PG_HI21 275 /* Page-rel. ADRP imm. from 32:12. */ +#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 /* Likewise; no overflow check. */ +#define R_AARCH64_ADD_ABS_LO12_NC 277 /* Dir. ADD imm. from bits 11:0. */ +#define R_AARCH64_LDST8_ABS_LO12_NC 278 /* Likewise for LD/ST; no check. */ +#define R_AARCH64_TSTBR14 279 /* PC-rel. TBZ/TBNZ imm. from 15:2. */ +#define R_AARCH64_CONDBR19 280 /* PC-rel. cond. br. imm. from 20:2. */ +#define R_AARCH64_JUMP26 282 /* PC-rel. B imm. from bits 27:2. */ +#define R_AARCH64_CALL26 283 /* Likewise for CALL. */ +#define R_AARCH64_LDST16_ABS_LO12_NC 284 /* Dir. ADD imm. from bits 11:1. */ +#define R_AARCH64_LDST32_ABS_LO12_NC 285 /* Likewise for bits 11:2. */ +#define R_AARCH64_LDST64_ABS_LO12_NC 286 /* Likewise for bits 11:3. */ +#define R_AARCH64_MOVW_PREL_G0 287 /* PC-rel. MOV{N,Z} imm. from 15:0. */ +#define R_AARCH64_MOVW_PREL_G0_NC 288 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_PREL_G1 289 /* PC-rel. MOV{N,Z} imm. from 31:16. */ +#define R_AARCH64_MOVW_PREL_G1_NC 290 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_PREL_G2 291 /* PC-rel. MOV{N,Z} imm. from 47:32. */ +#define R_AARCH64_MOVW_PREL_G2_NC 292 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_PREL_G3 293 /* PC-rel. MOV{N,Z} imm. from 63:48. */ +#define R_AARCH64_LDST128_ABS_LO12_NC 299 /* Dir. ADD imm. from bits 11:4. */ +#define R_AARCH64_MOVW_GOTOFF_G0 300 /* GOT-rel. off. MOV{N,Z} imm. 15:0. */ +#define R_AARCH64_MOVW_GOTOFF_G0_NC 301 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_GOTOFF_G1 302 /* GOT-rel. o. MOV{N,Z} imm. 31:16. */ +#define R_AARCH64_MOVW_GOTOFF_G1_NC 303 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_GOTOFF_G2 304 /* GOT-rel. o. MOV{N,Z} imm. 47:32. */ +#define R_AARCH64_MOVW_GOTOFF_G2_NC 305 /* Likewise for MOVK; no check. */ +#define R_AARCH64_MOVW_GOTOFF_G3 306 /* GOT-rel. o. MOV{N,Z} imm. 63:48. */ +#define R_AARCH64_GOTREL64 307 /* GOT-relative 64-bit. */ +#define R_AARCH64_GOTREL32 308 /* GOT-relative 32-bit. */ +#define R_AARCH64_GOT_LD_PREL19 309 /* PC-rel. GOT off. load imm. 20:2. */ +#define R_AARCH64_LD64_GOTOFF_LO15 310 /* GOT-rel. off. LD/ST imm. 14:3. */ +#define R_AARCH64_ADR_GOT_PAGE 311 /* P-page-rel. GOT off. ADRP 32:12. */ +#define R_AARCH64_LD64_GOT_LO12_NC 312 /* Dir. GOT off. LD/ST imm. 11:3. */ +#define R_AARCH64_LD64_GOTPAGE_LO15 313 /* GOT-page-rel. GOT off. LD/ST 14:3 */ +#define R_AARCH64_TLSGD_ADR_PREL21 512 /* PC-relative ADR imm. 20:0. */ +#define R_AARCH64_TLSGD_ADR_PAGE21 513 /* page-rel. ADRP imm. 32:12. */ +#define R_AARCH64_TLSGD_ADD_LO12_NC 514 /* direct ADD imm. from 11:0. */ +#define R_AARCH64_TLSGD_MOVW_G1 515 /* GOT-rel. MOV{N,Z} 31:16. */ +#define R_AARCH64_TLSGD_MOVW_G0_NC 516 /* GOT-rel. MOVK imm. 15:0. */ +#define R_AARCH64_TLSLD_ADR_PREL21 517 /* Like 512; local dynamic model. */ +#define R_AARCH64_TLSLD_ADR_PAGE21 518 /* Like 513; local dynamic model. */ +#define R_AARCH64_TLSLD_ADD_LO12_NC 519 /* Like 514; local dynamic model. */ +#define R_AARCH64_TLSLD_MOVW_G1 520 /* Like 515; local dynamic model. */ +#define R_AARCH64_TLSLD_MOVW_G0_NC 521 /* Like 516; local dynamic model. */ +#define R_AARCH64_TLSLD_LD_PREL19 522 /* TLS PC-rel. load imm. 20:2. */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523 /* TLS DTP-rel. MOV{N,Z} 47:32. */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524 /* TLS DTP-rel. MOV{N,Z} 31:16. */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525 /* Likewise; MOVK; no check. */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526 /* TLS DTP-rel. MOV{N,Z} 15:0. */ +#define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 527 /* Likewise; MOVK; no check. */ +#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 /* DTP-rel. ADD imm. from 23:12. */ +#define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529 /* DTP-rel. ADD imm. from 11:0. */ +#define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530 /* Likewise; no ovfl. check. */ +#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531 /* DTP-rel. LD/ST imm. 11:0. */ +#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532 /* Likewise; no check. */ +#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533 /* DTP-rel. LD/ST imm. 11:1. */ +#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534 /* Likewise; no check. */ +#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535 /* DTP-rel. LD/ST imm. 11:2. */ +#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536 /* Likewise; no check. */ +#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537 /* DTP-rel. LD/ST imm. 11:3. */ +#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538 /* Likewise; no check. */ +#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539 /* GOT-rel. MOV{N,Z} 31:16. */ +#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540 /* GOT-rel. MOVK 15:0. */ +#define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541 /* Page-rel. ADRP 32:12. */ +#define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542 /* Direct LD off. 11:3. */ +#define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543 /* PC-rel. load imm. 20:2. */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G2 544 /* TLS TP-rel. MOV{N,Z} 47:32. */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G1 545 /* TLS TP-rel. MOV{N,Z} 31:16. */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G1_NC 546 /* Likewise; MOVK; no check. */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G0 547 /* TLS TP-rel. MOV{N,Z} 15:0. */ +#define R_AARCH64_TLSLE_MOVW_TPREL_G0_NC 548 /* Likewise; MOVK; no check. */ +#define R_AARCH64_TLSLE_ADD_TPREL_HI12 549 /* TP-rel. ADD imm. 23:12. */ +#define R_AARCH64_TLSLE_ADD_TPREL_LO12 550 /* TP-rel. ADD imm. 11:0. */ +#define R_AARCH64_TLSLE_ADD_TPREL_LO12_NC 551 /* Likewise; no ovfl. check. */ +#define R_AARCH64_TLSLE_LDST8_TPREL_LO12 552 /* TP-rel. LD/ST off. 11:0. */ +#define R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC 553 /* Likewise; no ovfl. check. */ +#define R_AARCH64_TLSLE_LDST16_TPREL_LO12 554 /* TP-rel. LD/ST off. 11:1. */ +#define R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC 555 /* Likewise; no check. */ +#define R_AARCH64_TLSLE_LDST32_TPREL_LO12 556 /* TP-rel. LD/ST off. 11:2. */ +#define R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC 557 /* Likewise; no check. */ +#define R_AARCH64_TLSLE_LDST64_TPREL_LO12 558 /* TP-rel. LD/ST off. 11:3. */ +#define R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC 559 /* Likewise; no check. */ +#define R_AARCH64_TLSDESC_LD_PREL19 560 /* PC-rel. load immediate 20:2. */ +#define R_AARCH64_TLSDESC_ADR_PREL21 561 /* PC-rel. ADR immediate 20:0. */ +#define R_AARCH64_TLSDESC_ADR_PAGE21 562 /* Page-rel. ADRP imm. 32:12. */ +#define R_AARCH64_TLSDESC_LD64_LO12 563 /* Direct LD off. from 11:3. */ +#define R_AARCH64_TLSDESC_ADD_LO12 564 /* Direct ADD imm. from 11:0. */ +#define R_AARCH64_TLSDESC_OFF_G1 565 /* GOT-rel. MOV{N,Z} imm. 31:16. */ +#define R_AARCH64_TLSDESC_OFF_G0_NC 566 /* GOT-rel. MOVK imm. 15:0; no ck. */ +#define R_AARCH64_TLSDESC_LDR 567 /* Relax LDR. */ +#define R_AARCH64_TLSDESC_ADD 568 /* Relax ADD. */ +#define R_AARCH64_TLSDESC_CALL 569 /* Relax BLR. */ +#define R_AARCH64_TLSLE_LDST128_TPREL_LO12 570 /* TP-rel. LD/ST off. 11:4. */ +#define R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC 571 /* Likewise; no check. */ +#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12 572 /* DTP-rel. LD/ST imm. 11:4. */ +#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC 573 /* Likewise; no check. */ +#define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */ +#define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */ +#define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */ +#define R_AARCH64_RELATIVE 1027 /* Adjust by program base. */ +#define R_AARCH64_TLS_DTPMOD64 1028 /* Module number, 64 bit. */ +#define R_AARCH64_TLS_DTPREL64 1029 /* Module-relative offset, 64 bit. */ +#define R_AARCH64_TLS_TPREL64 1030 /* TP-relative offset, 64 bit. */ +#define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */ +#define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */ +/* Keep this the last entry. */ +#define R_AARCH64_NUM 1033 + +/* ARM relocs. */ + +#define R_ARM_NONE 0 /* No reloc */ +#define R_ARM_PC24 1 /* PC relative 26 bit branch */ +#define R_ARM_ABS32 2 /* Direct 32 bit */ +#define R_ARM_REL32 3 /* PC relative 32 bit */ +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 /* Direct 16 bit */ +#define R_ARM_ABS12 6 /* Direct 12 bit */ +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 /* Direct 8 bit */ +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 /* Obsolete static relocation. */ +#define R_ARM_TLS_DESC 13 /* Dynamic relocation. */ +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ +#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ +#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ +#define R_ARM_COPY 20 /* Copy symbol at runtime */ +#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ +#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ +#define R_ARM_RELATIVE 23 /* Adjust by program base */ +#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ +#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ +#define R_ARM_GOT32 26 /* 32 bit GOT entry */ +#define R_ARM_PLT32 27 /* 32 bit PLT address */ +#define R_ARM_CALL 28 +#define R_ARM_JUMP24 29 +#define R_ARM_THM_JUMP24 30 +#define R_ARM_BASE_ABS 31 /* Adjust by program base. */ +#define R_ARM_ALU_PCREL_7_0 32 +#define R_ARM_ALU_PCREL_15_8 33 +#define R_ARM_ALU_PCREL_23_15 34 +#define R_ARM_LDR_SBREL_11_0 35 +#define R_ARM_ALU_SBREL_19_12 36 +#define R_ARM_ALU_SBREL_27_20 37 +#define R_ARM_TARGET1 38 +#define R_ARM_SBREL31 39 /* Program base relative. */ +#define R_ARM_V4BX 40 +#define R_ARM_TARGET2 41 +#define R_ARM_PREL31 42 +#define R_ARM_MOVW_ABS_NC 43 +#define R_ARM_MOVT_ABS 44 +#define R_ARM_MOVW_PREL_NC 45 /* PC relative 16-bit (MOVW). */ +#define R_ARM_MOVT_PREL 46 /* PC relative (MOVT). */ +#define R_ARM_THM_MOVW_ABS_NC 47 +#define R_ARM_THM_MOVT_ABS 48 +/* Values from 49 to 89 are not yet used/handled by tcc. */ +#define R_ARM_TLS_GOTDESC 90 +#define R_ARM_TLS_CALL 91 +#define R_ARM_TLS_DESCSEQ 92 +#define R_ARM_THM_TLS_CALL 93 +#define R_ARM_GOT_PREL 96 +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ +#define R_ARM_THM_PC9 103 /* thumb conditional branch */ +#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic + thread local data */ +#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic + thread local data */ +#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS + block */ +#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of + static TLS block offset */ +#define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static + TLS block */ +#define R_ARM_THM_TLS_DESCSEQ 129 +#define R_ARM_IRELATIVE 160 +#define R_ARM_RXPC25 249 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS22 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 +/* Keep this the last entry. */ +#define R_ARM_NUM 256 + +/* TMS320C67xx specific declarations */ + +/* XXX: no ELF standard yet*/ + +/* TMS320C67xx relocs. */ +#define R_C60_32 1 +#define R_C60_GOT32 3 /* 32 bit GOT entry */ +#define R_C60_PLT32 4 /* 32 bit PLT address */ +#define R_C60_COPY 5 /* Copy symbol at runtime */ +#define R_C60_GLOB_DAT 6 /* Create GOT entry */ +#define R_C60_JMP_SLOT 7 /* Create PLT entry */ +#define R_C60_RELATIVE 8 /* Adjust by program base */ +#define R_C60_GOTOFF 9 /* 32 bit offset to GOT */ +#define R_C60_GOTPC 10 /* 32 bit PC relative offset to GOT */ + +#define R_C60LO16 0x54 /* low 16 bit MVKL embedded */ +#define R_C60HI16 0x55 /* high 16 bit MVKH embedded */ +/* Keep this the last entry. */ +#define R_C60_NUM 0x56 + +/* IA-64 specific declarations. */ + +/* Processor specific flags for the Ehdr e_flags field. */ +#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ +#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ +#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ + +/* Processor specific values for the Phdr p_type field. */ +#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ +#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ +#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) +#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) +#define PT_IA_64_HP_STACK (PT_LOOS + 0x14) + +/* Processor specific flags for the Phdr p_flags field. */ +#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Shdr sh_type field. */ +#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ +#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ + +/* Processor specific flags for the Shdr sh_flags field. */ +#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ +#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Dyn d_tag field. */ +#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) +#define DT_IA_64_NUM 1 + +/* IA-64 relocations. */ +#define R_IA64_NONE 0x00 /* none */ +#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ +#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ +#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ +#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ +#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ +#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ +#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ +#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ +#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ +#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ +#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ +#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ +#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ +#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ +#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ +#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ +#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ +#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ +#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ +#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ +#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ +#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ +#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ +#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ +#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ +#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ +#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ +#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ +#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ +#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ +#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ +#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ +#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ +#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ +#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ +#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ +#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ +#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ +#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ +#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ +#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ +#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ +#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ +#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ +#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ +#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ +#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ +#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ +#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ +#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ +#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ +#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ +#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ +#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ +#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ +#define R_IA64_COPY 0x84 /* copy relocation */ +#define R_IA64_SUB 0x85 /* Addend and symbol difference */ +#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ +#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ +#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ +#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ +#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ +#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ +#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ +#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ +#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ +#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ +#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ +#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ +#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ +#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ +#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ +#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ + +/* SH specific declarations */ + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_SH_MACH_MASK 0x1f +#define EF_SH_UNKNOWN 0x0 +#define EF_SH1 0x1 +#define EF_SH2 0x2 +#define EF_SH3 0x3 +#define EF_SH_DSP 0x4 +#define EF_SH3_DSP 0x5 +#define EF_SH4AL_DSP 0x6 +#define EF_SH3E 0x8 +#define EF_SH4 0x9 +#define EF_SH2E 0xb +#define EF_SH4A 0xc +#define EF_SH2A 0xd +#define EF_SH4_NOFPU 0x10 +#define EF_SH4A_NOFPU 0x11 +#define EF_SH4_NOMMU_NOFPU 0x12 +#define EF_SH2A_NOFPU 0x13 +#define EF_SH3_NOMMU 0x14 +#define EF_SH2A_SH4_NOFPU 0x15 +#define EF_SH2A_SH3_NOFPU 0x16 +#define EF_SH2A_SH4 0x17 +#define EF_SH2A_SH3E 0x18 + +/* SH relocs. */ +#define R_SH_NONE 0 +#define R_SH_DIR32 1 +#define R_SH_REL32 2 +#define R_SH_DIR8WPN 3 +#define R_SH_IND12W 4 +#define R_SH_DIR8WPL 5 +#define R_SH_DIR8WPZ 6 +#define R_SH_DIR8BP 7 +#define R_SH_DIR8W 8 +#define R_SH_DIR8L 9 +#define R_SH_SWITCH16 25 +#define R_SH_SWITCH32 26 +#define R_SH_USES 27 +#define R_SH_COUNT 28 +#define R_SH_ALIGN 29 +#define R_SH_CODE 30 +#define R_SH_DATA 31 +#define R_SH_LABEL 32 +#define R_SH_SWITCH8 33 +#define R_SH_GNU_VTINHERIT 34 +#define R_SH_GNU_VTENTRY 35 +#define R_SH_TLS_GD_32 144 +#define R_SH_TLS_LD_32 145 +#define R_SH_TLS_LDO_32 146 +#define R_SH_TLS_IE_32 147 +#define R_SH_TLS_LE_32 148 +#define R_SH_TLS_DTPMOD32 149 +#define R_SH_TLS_DTPOFF32 150 +#define R_SH_TLS_TPOFF32 151 +#define R_SH_GOT32 160 +#define R_SH_PLT32 161 +#define R_SH_COPY 162 +#define R_SH_GLOB_DAT 163 +#define R_SH_JMP_SLOT 164 +#define R_SH_RELATIVE 165 +#define R_SH_GOTOFF 166 +#define R_SH_GOTPC 167 +/* Keep this the last entry. */ +#define R_SH_NUM 256 + +/* S/390 specific definitions. */ + +/* Valid values for the e_flags field. */ + +#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */ + +/* Additional s390 relocs */ + +#define R_390_NONE 0 /* No reloc. */ +#define R_390_8 1 /* Direct 8 bit. */ +#define R_390_12 2 /* Direct 12 bit. */ +#define R_390_16 3 /* Direct 16 bit. */ +#define R_390_32 4 /* Direct 32 bit. */ +#define R_390_PC32 5 /* PC relative 32 bit. */ +#define R_390_GOT12 6 /* 12 bit GOT offset. */ +#define R_390_GOT32 7 /* 32 bit GOT offset. */ +#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ +#define R_390_COPY 9 /* Copy symbol at runtime. */ +#define R_390_GLOB_DAT 10 /* Create GOT entry. */ +#define R_390_JMP_SLOT 11 /* Create PLT entry. */ +#define R_390_RELATIVE 12 /* Adjust by program base. */ +#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ +#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ +#define R_390_GOT16 15 /* 16 bit GOT offset. */ +#define R_390_PC16 16 /* PC relative 16 bit. */ +#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ +#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ +#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ +#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ +#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ +#define R_390_64 22 /* Direct 64 bit. */ +#define R_390_PC64 23 /* PC relative 64 bit. */ +#define R_390_GOT64 24 /* 64 bit GOT offset. */ +#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ +#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ +#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ +#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ +#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ +#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ +#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ +#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ +#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ +#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ +#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ +#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ +#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ +#define R_390_TLS_GDCALL 38 /* Tag for function call in general + dynamic TLS code. */ +#define R_390_TLS_LDCALL 39 /* Tag for function call in local + dynamic TLS code. */ +#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic + thread local data. */ +#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic + thread local data. */ +#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic + thread local data in LE code. */ +#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic + thread local data in LE code. */ +#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS + block. */ +#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS + block. */ +#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ +#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ +#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS + block. */ +#define R_390_20 57 /* Direct 20 bit. */ +#define R_390_GOT20 58 /* 20 bit GOT offset. */ +#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */ +#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS + block offset. */ +#define R_390_IRELATIVE 61 /* STT_GNU_IFUNC relocation. */ +/* Keep this the last entry. */ +#define R_390_NUM 62 + + +/* CRIS relocations. */ +#define R_CRIS_NONE 0 +#define R_CRIS_8 1 +#define R_CRIS_16 2 +#define R_CRIS_32 3 +#define R_CRIS_8_PCREL 4 +#define R_CRIS_16_PCREL 5 +#define R_CRIS_32_PCREL 6 +#define R_CRIS_GNU_VTINHERIT 7 +#define R_CRIS_GNU_VTENTRY 8 +#define R_CRIS_COPY 9 +#define R_CRIS_GLOB_DAT 10 +#define R_CRIS_JUMP_SLOT 11 +#define R_CRIS_RELATIVE 12 +#define R_CRIS_16_GOT 13 +#define R_CRIS_32_GOT 14 +#define R_CRIS_16_GOTPLT 15 +#define R_CRIS_32_GOTPLT 16 +#define R_CRIS_32_GOTREL 17 +#define R_CRIS_32_PLT_GOTREL 18 +#define R_CRIS_32_PLT_PCREL 19 + +#define R_CRIS_NUM 20 + + +/* AMD x86-64 relocations. */ +#define R_X86_64_NONE 0 /* No reloc */ +#define R_X86_64_64 1 /* Direct 64 bit */ +#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ +#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ +#define R_X86_64_PLT32 4 /* 32 bit PLT address */ +#define R_X86_64_COPY 5 /* Copy symbol at runtime */ +#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ +#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ +#define R_X86_64_RELATIVE 8 /* Adjust by program base */ +#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative + offset to GOT */ +#define R_X86_64_32 10 /* Direct 32 bit zero extended */ +#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#define R_X86_64_16 12 /* Direct 16 bit zero extended */ +#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ +#define R_X86_64_8 14 /* Direct 8 bit sign extended */ +#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ +#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ +#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ +#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ +#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset + to two GOT entries for GD symbol */ +#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset + to two GOT entries for LD symbol */ +#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ +#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset + to GOT entry for IE symbol */ +#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ +#define R_X86_64_PC64 24 /* PC relative 64 bit */ +#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */ +#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative + offset to GOT */ +#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */ +#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset + to GOT entry */ +#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */ +#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */ +#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset + to PLT entry */ +#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */ +#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */ +#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */ +#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS + descriptor. */ +#define R_X86_64_TLSDESC 36 /* TLS descriptor. */ +#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */ +#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */ +#define R_X86_64_GOTPCRELX 41 /* like GOTPCREL, but optionally with + linker optimizations */ +#define R_X86_64_REX_GOTPCRELX 42 /* like GOTPCRELX, but a REX prefix + is present */ + +#define R_X86_64_NUM 43 + +/* x86-64 sh_type values. */ +#define SHT_X86_64_UNWIND 0x70000001 /* Unwind information. */ + +/* AM33 relocations. */ +#define R_MN10300_NONE 0 /* No reloc. */ +#define R_MN10300_32 1 /* Direct 32 bit. */ +#define R_MN10300_16 2 /* Direct 16 bit. */ +#define R_MN10300_8 3 /* Direct 8 bit. */ +#define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */ +#define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */ +#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */ +#define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */ +#define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */ +#define R_MN10300_24 9 /* Direct 24 bit. */ +#define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */ +#define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */ +#define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */ +#define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */ +#define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */ +#define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */ +#define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */ +#define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */ +#define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */ +#define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */ +#define R_MN10300_COPY 20 /* Copy symbol at runtime. */ +#define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */ +#define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */ +#define R_MN10300_RELATIVE 23 /* Adjust by program base. */ +#define R_MN10300_TLS_GD 24 /* 32-bit offset for global dynamic. */ +#define R_MN10300_TLS_LD 25 /* 32-bit offset for local dynamic. */ +#define R_MN10300_TLS_LDO 26 /* Module-relative offset. */ +#define R_MN10300_TLS_GOTIE 27 /* GOT offset for static TLS block + offset. */ +#define R_MN10300_TLS_IE 28 /* GOT address for static TLS block + offset. */ +#define R_MN10300_TLS_LE 29 /* Offset relative to static TLS + block. */ +#define R_MN10300_TLS_DTPMOD 30 /* ID of module containing symbol. */ +#define R_MN10300_TLS_DTPOFF 31 /* Offset in module TLS block. */ +#define R_MN10300_TLS_TPOFF 32 /* Offset in static TLS block. */ +#define R_MN10300_SYM_DIFF 33 /* Adjustment for next reloc as needed + by linker relaxation. */ +#define R_MN10300_ALIGN 34 /* Alignment requirement for linker + relaxation. */ +#define R_MN10300_NUM 35 + + +/* M32R relocs. */ +#define R_M32R_NONE 0 /* No reloc. */ +#define R_M32R_16 1 /* Direct 16 bit. */ +#define R_M32R_32 2 /* Direct 32 bit. */ +#define R_M32R_24 3 /* Direct 24 bit. */ +#define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */ +#define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */ +#define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */ +#define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */ +#define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */ +#define R_M32R_LO16 9 /* Low 16 bit. */ +#define R_M32R_SDA16 10 /* 16 bit offset in SDA. */ +#define R_M32R_GNU_VTINHERIT 11 +#define R_M32R_GNU_VTENTRY 12 +/* M32R relocs use SHT_RELA. */ +#define R_M32R_16_RELA 33 /* Direct 16 bit. */ +#define R_M32R_32_RELA 34 /* Direct 32 bit. */ +#define R_M32R_24_RELA 35 /* Direct 24 bit. */ +#define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */ +#define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */ +#define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */ +#define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */ +#define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */ +#define R_M32R_LO16_RELA 41 /* Low 16 bit */ +#define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */ +#define R_M32R_RELA_GNU_VTINHERIT 43 +#define R_M32R_RELA_GNU_VTENTRY 44 +#define R_M32R_REL32 45 /* PC relative 32 bit. */ + +#define R_M32R_GOT24 48 /* 24 bit GOT entry */ +#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */ +#define R_M32R_COPY 50 /* Copy symbol at runtime */ +#define R_M32R_GLOB_DAT 51 /* Create GOT entry */ +#define R_M32R_JMP_SLOT 52 /* Create PLT entry */ +#define R_M32R_RELATIVE 53 /* Adjust by program base */ +#define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */ +#define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */ +#define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned + low */ +#define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed + low */ +#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */ +#define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to + GOT with unsigned low */ +#define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to + GOT with signed low */ +#define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to + GOT */ +#define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT + with unsigned low */ +#define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT + with signed low */ +#define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */ +#define R_M32R_NUM 256 /* Keep this the last entry. */ + + +/* TILEPro relocations. */ +#define R_TILEPRO_NONE 0 /* No reloc */ +#define R_TILEPRO_32 1 /* Direct 32 bit */ +#define R_TILEPRO_16 2 /* Direct 16 bit */ +#define R_TILEPRO_8 3 /* Direct 8 bit */ +#define R_TILEPRO_32_PCREL 4 /* PC relative 32 bit */ +#define R_TILEPRO_16_PCREL 5 /* PC relative 16 bit */ +#define R_TILEPRO_8_PCREL 6 /* PC relative 8 bit */ +#define R_TILEPRO_LO16 7 /* Low 16 bit */ +#define R_TILEPRO_HI16 8 /* High 16 bit */ +#define R_TILEPRO_HA16 9 /* High 16 bit, adjusted */ +#define R_TILEPRO_COPY 10 /* Copy relocation */ +#define R_TILEPRO_GLOB_DAT 11 /* Create GOT entry */ +#define R_TILEPRO_JMP_SLOT 12 /* Create PLT entry */ +#define R_TILEPRO_RELATIVE 13 /* Adjust by program base */ +#define R_TILEPRO_BROFF_X1 14 /* X1 pipe branch offset */ +#define R_TILEPRO_JOFFLONG_X1 15 /* X1 pipe jump offset */ +#define R_TILEPRO_JOFFLONG_X1_PLT 16 /* X1 pipe jump offset to PLT */ +#define R_TILEPRO_IMM8_X0 17 /* X0 pipe 8-bit */ +#define R_TILEPRO_IMM8_Y0 18 /* Y0 pipe 8-bit */ +#define R_TILEPRO_IMM8_X1 19 /* X1 pipe 8-bit */ +#define R_TILEPRO_IMM8_Y1 20 /* Y1 pipe 8-bit */ +#define R_TILEPRO_MT_IMM15_X1 21 /* X1 pipe mtspr */ +#define R_TILEPRO_MF_IMM15_X1 22 /* X1 pipe mfspr */ +#define R_TILEPRO_IMM16_X0 23 /* X0 pipe 16-bit */ +#define R_TILEPRO_IMM16_X1 24 /* X1 pipe 16-bit */ +#define R_TILEPRO_IMM16_X0_LO 25 /* X0 pipe low 16-bit */ +#define R_TILEPRO_IMM16_X1_LO 26 /* X1 pipe low 16-bit */ +#define R_TILEPRO_IMM16_X0_HI 27 /* X0 pipe high 16-bit */ +#define R_TILEPRO_IMM16_X1_HI 28 /* X1 pipe high 16-bit */ +#define R_TILEPRO_IMM16_X0_HA 29 /* X0 pipe high 16-bit, adjusted */ +#define R_TILEPRO_IMM16_X1_HA 30 /* X1 pipe high 16-bit, adjusted */ +#define R_TILEPRO_IMM16_X0_PCREL 31 /* X0 pipe PC relative 16 bit */ +#define R_TILEPRO_IMM16_X1_PCREL 32 /* X1 pipe PC relative 16 bit */ +#define R_TILEPRO_IMM16_X0_LO_PCREL 33 /* X0 pipe PC relative low 16 bit */ +#define R_TILEPRO_IMM16_X1_LO_PCREL 34 /* X1 pipe PC relative low 16 bit */ +#define R_TILEPRO_IMM16_X0_HI_PCREL 35 /* X0 pipe PC relative high 16 bit */ +#define R_TILEPRO_IMM16_X1_HI_PCREL 36 /* X1 pipe PC relative high 16 bit */ +#define R_TILEPRO_IMM16_X0_HA_PCREL 37 /* X0 pipe PC relative ha() 16 bit */ +#define R_TILEPRO_IMM16_X1_HA_PCREL 38 /* X1 pipe PC relative ha() 16 bit */ +#define R_TILEPRO_IMM16_X0_GOT 39 /* X0 pipe 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X1_GOT 40 /* X1 pipe 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X0_GOT_LO 41 /* X0 pipe low 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X1_GOT_LO 42 /* X1 pipe low 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X0_GOT_HI 43 /* X0 pipe high 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X1_GOT_HI 44 /* X1 pipe high 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X0_GOT_HA 45 /* X0 pipe ha() 16-bit GOT offset */ +#define R_TILEPRO_IMM16_X1_GOT_HA 46 /* X1 pipe ha() 16-bit GOT offset */ +#define R_TILEPRO_MMSTART_X0 47 /* X0 pipe mm "start" */ +#define R_TILEPRO_MMEND_X0 48 /* X0 pipe mm "end" */ +#define R_TILEPRO_MMSTART_X1 49 /* X1 pipe mm "start" */ +#define R_TILEPRO_MMEND_X1 50 /* X1 pipe mm "end" */ +#define R_TILEPRO_SHAMT_X0 51 /* X0 pipe shift amount */ +#define R_TILEPRO_SHAMT_X1 52 /* X1 pipe shift amount */ +#define R_TILEPRO_SHAMT_Y0 53 /* Y0 pipe shift amount */ +#define R_TILEPRO_SHAMT_Y1 54 /* Y1 pipe shift amount */ +#define R_TILEPRO_DEST_IMM8_X1 55 /* X1 pipe destination 8-bit */ +/* Relocs 56-59 are currently not defined. */ +#define R_TILEPRO_TLS_GD_CALL 60 /* "jal" for TLS GD */ +#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61 /* X0 pipe "addi" for TLS GD */ +#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62 /* X1 pipe "addi" for TLS GD */ +#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63 /* Y0 pipe "addi" for TLS GD */ +#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64 /* Y1 pipe "addi" for TLS GD */ +#define R_TILEPRO_TLS_IE_LOAD 65 /* "lw_tls" for TLS IE */ +#define R_TILEPRO_IMM16_X0_TLS_GD 66 /* X0 pipe 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X1_TLS_GD 67 /* X1 pipe 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68 /* X0 pipe low 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69 /* X1 pipe low 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70 /* X0 pipe high 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71 /* X1 pipe high 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72 /* X0 pipe ha() 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73 /* X1 pipe ha() 16-bit TLS GD offset */ +#define R_TILEPRO_IMM16_X0_TLS_IE 74 /* X0 pipe 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X1_TLS_IE 75 /* X1 pipe 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76 /* X0 pipe low 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77 /* X1 pipe low 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78 /* X0 pipe high 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79 /* X1 pipe high 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80 /* X0 pipe ha() 16-bit TLS IE offset */ +#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81 /* X1 pipe ha() 16-bit TLS IE offset */ +#define R_TILEPRO_TLS_DTPMOD32 82 /* ID of module containing symbol */ +#define R_TILEPRO_TLS_DTPOFF32 83 /* Offset in TLS block */ +#define R_TILEPRO_TLS_TPOFF32 84 /* Offset in static TLS block */ +#define R_TILEPRO_IMM16_X0_TLS_LE 85 /* X0 pipe 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X1_TLS_LE 86 /* X1 pipe 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87 /* X0 pipe low 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88 /* X1 pipe low 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89 /* X0 pipe high 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90 /* X1 pipe high 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91 /* X0 pipe ha() 16-bit TLS LE offset */ +#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92 /* X1 pipe ha() 16-bit TLS LE offset */ + +#define R_TILEPRO_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ +#define R_TILEPRO_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ + +#define R_TILEPRO_NUM 130 + + +/* TILE-Gx relocations. */ +#define R_TILEGX_NONE 0 /* No reloc */ +#define R_TILEGX_64 1 /* Direct 64 bit */ +#define R_TILEGX_32 2 /* Direct 32 bit */ +#define R_TILEGX_16 3 /* Direct 16 bit */ +#define R_TILEGX_8 4 /* Direct 8 bit */ +#define R_TILEGX_64_PCREL 5 /* PC relative 64 bit */ +#define R_TILEGX_32_PCREL 6 /* PC relative 32 bit */ +#define R_TILEGX_16_PCREL 7 /* PC relative 16 bit */ +#define R_TILEGX_8_PCREL 8 /* PC relative 8 bit */ +#define R_TILEGX_HW0 9 /* hword 0 16-bit */ +#define R_TILEGX_HW1 10 /* hword 1 16-bit */ +#define R_TILEGX_HW2 11 /* hword 2 16-bit */ +#define R_TILEGX_HW3 12 /* hword 3 16-bit */ +#define R_TILEGX_HW0_LAST 13 /* last hword 0 16-bit */ +#define R_TILEGX_HW1_LAST 14 /* last hword 1 16-bit */ +#define R_TILEGX_HW2_LAST 15 /* last hword 2 16-bit */ +#define R_TILEGX_COPY 16 /* Copy relocation */ +#define R_TILEGX_GLOB_DAT 17 /* Create GOT entry */ +#define R_TILEGX_JMP_SLOT 18 /* Create PLT entry */ +#define R_TILEGX_RELATIVE 19 /* Adjust by program base */ +#define R_TILEGX_BROFF_X1 20 /* X1 pipe branch offset */ +#define R_TILEGX_JUMPOFF_X1 21 /* X1 pipe jump offset */ +#define R_TILEGX_JUMPOFF_X1_PLT 22 /* X1 pipe jump offset to PLT */ +#define R_TILEGX_IMM8_X0 23 /* X0 pipe 8-bit */ +#define R_TILEGX_IMM8_Y0 24 /* Y0 pipe 8-bit */ +#define R_TILEGX_IMM8_X1 25 /* X1 pipe 8-bit */ +#define R_TILEGX_IMM8_Y1 26 /* Y1 pipe 8-bit */ +#define R_TILEGX_DEST_IMM8_X1 27 /* X1 pipe destination 8-bit */ +#define R_TILEGX_MT_IMM14_X1 28 /* X1 pipe mtspr */ +#define R_TILEGX_MF_IMM14_X1 29 /* X1 pipe mfspr */ +#define R_TILEGX_MMSTART_X0 30 /* X0 pipe mm "start" */ +#define R_TILEGX_MMEND_X0 31 /* X0 pipe mm "end" */ +#define R_TILEGX_SHAMT_X0 32 /* X0 pipe shift amount */ +#define R_TILEGX_SHAMT_X1 33 /* X1 pipe shift amount */ +#define R_TILEGX_SHAMT_Y0 34 /* Y0 pipe shift amount */ +#define R_TILEGX_SHAMT_Y1 35 /* Y1 pipe shift amount */ +#define R_TILEGX_IMM16_X0_HW0 36 /* X0 pipe hword 0 */ +#define R_TILEGX_IMM16_X1_HW0 37 /* X1 pipe hword 0 */ +#define R_TILEGX_IMM16_X0_HW1 38 /* X0 pipe hword 1 */ +#define R_TILEGX_IMM16_X1_HW1 39 /* X1 pipe hword 1 */ +#define R_TILEGX_IMM16_X0_HW2 40 /* X0 pipe hword 2 */ +#define R_TILEGX_IMM16_X1_HW2 41 /* X1 pipe hword 2 */ +#define R_TILEGX_IMM16_X0_HW3 42 /* X0 pipe hword 3 */ +#define R_TILEGX_IMM16_X1_HW3 43 /* X1 pipe hword 3 */ +#define R_TILEGX_IMM16_X0_HW0_LAST 44 /* X0 pipe last hword 0 */ +#define R_TILEGX_IMM16_X1_HW0_LAST 45 /* X1 pipe last hword 0 */ +#define R_TILEGX_IMM16_X0_HW1_LAST 46 /* X0 pipe last hword 1 */ +#define R_TILEGX_IMM16_X1_HW1_LAST 47 /* X1 pipe last hword 1 */ +#define R_TILEGX_IMM16_X0_HW2_LAST 48 /* X0 pipe last hword 2 */ +#define R_TILEGX_IMM16_X1_HW2_LAST 49 /* X1 pipe last hword 2 */ +#define R_TILEGX_IMM16_X0_HW0_PCREL 50 /* X0 pipe PC relative hword 0 */ +#define R_TILEGX_IMM16_X1_HW0_PCREL 51 /* X1 pipe PC relative hword 0 */ +#define R_TILEGX_IMM16_X0_HW1_PCREL 52 /* X0 pipe PC relative hword 1 */ +#define R_TILEGX_IMM16_X1_HW1_PCREL 53 /* X1 pipe PC relative hword 1 */ +#define R_TILEGX_IMM16_X0_HW2_PCREL 54 /* X0 pipe PC relative hword 2 */ +#define R_TILEGX_IMM16_X1_HW2_PCREL 55 /* X1 pipe PC relative hword 2 */ +#define R_TILEGX_IMM16_X0_HW3_PCREL 56 /* X0 pipe PC relative hword 3 */ +#define R_TILEGX_IMM16_X1_HW3_PCREL 57 /* X1 pipe PC relative hword 3 */ +#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */ +#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */ +#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */ +#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */ +#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */ +#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */ +#define R_TILEGX_IMM16_X0_HW0_GOT 64 /* X0 pipe hword 0 GOT offset */ +#define R_TILEGX_IMM16_X1_HW0_GOT 65 /* X1 pipe hword 0 GOT offset */ +#define R_TILEGX_IMM16_X0_HW0_PLT_PCREL 66 /* X0 pipe PC-rel PLT hword 0 */ +#define R_TILEGX_IMM16_X1_HW0_PLT_PCREL 67 /* X1 pipe PC-rel PLT hword 0 */ +#define R_TILEGX_IMM16_X0_HW1_PLT_PCREL 68 /* X0 pipe PC-rel PLT hword 1 */ +#define R_TILEGX_IMM16_X1_HW1_PLT_PCREL 69 /* X1 pipe PC-rel PLT hword 1 */ +#define R_TILEGX_IMM16_X0_HW2_PLT_PCREL 70 /* X0 pipe PC-rel PLT hword 2 */ +#define R_TILEGX_IMM16_X1_HW2_PLT_PCREL 71 /* X1 pipe PC-rel PLT hword 2 */ +#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */ +#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */ +#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */ +#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */ +#define R_TILEGX_IMM16_X0_HW3_PLT_PCREL 76 /* X0 pipe PC-rel PLT hword 3 */ +#define R_TILEGX_IMM16_X1_HW3_PLT_PCREL 77 /* X1 pipe PC-rel PLT hword 3 */ +#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78 /* X0 pipe hword 0 TLS GD offset */ +#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79 /* X1 pipe hword 0 TLS GD offset */ +#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80 /* X0 pipe hword 0 TLS LE offset */ +#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81 /* X1 pipe hword 0 TLS LE offset */ +#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */ +#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */ +#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */ +#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */ +#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */ +#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */ +#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */ +#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */ +/* Relocs 90-91 are currently not defined. */ +#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92 /* X0 pipe hword 0 TLS IE offset */ +#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93 /* X1 pipe hword 0 TLS IE offset */ +#define R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL 94 /* X0 pipe PC-rel PLT last hword 0 */ +#define R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL 95 /* X1 pipe PC-rel PLT last hword 0 */ +#define R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL 96 /* X0 pipe PC-rel PLT last hword 1 */ +#define R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL 97 /* X1 pipe PC-rel PLT last hword 1 */ +#define R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL 98 /* X0 pipe PC-rel PLT last hword 2 */ +#define R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL 99 /* X1 pipe PC-rel PLT last hword 2 */ +#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */ +#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */ +#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */ +#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */ +/* Relocs 104-105 are currently not defined. */ +#define R_TILEGX_TLS_DTPMOD64 106 /* 64-bit ID of symbol's module */ +#define R_TILEGX_TLS_DTPOFF64 107 /* 64-bit offset in TLS block */ +#define R_TILEGX_TLS_TPOFF64 108 /* 64-bit offset in static TLS block */ +#define R_TILEGX_TLS_DTPMOD32 109 /* 32-bit ID of symbol's module */ +#define R_TILEGX_TLS_DTPOFF32 110 /* 32-bit offset in TLS block */ +#define R_TILEGX_TLS_TPOFF32 111 /* 32-bit offset in static TLS block */ +#define R_TILEGX_TLS_GD_CALL 112 /* "jal" for TLS GD */ +#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113 /* X0 pipe "addi" for TLS GD */ +#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114 /* X1 pipe "addi" for TLS GD */ +#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115 /* Y0 pipe "addi" for TLS GD */ +#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116 /* Y1 pipe "addi" for TLS GD */ +#define R_TILEGX_TLS_IE_LOAD 117 /* "ld_tls" for TLS IE */ +#define R_TILEGX_IMM8_X0_TLS_ADD 118 /* X0 pipe "addi" for TLS GD/IE */ +#define R_TILEGX_IMM8_X1_TLS_ADD 119 /* X1 pipe "addi" for TLS GD/IE */ +#define R_TILEGX_IMM8_Y0_TLS_ADD 120 /* Y0 pipe "addi" for TLS GD/IE */ +#define R_TILEGX_IMM8_Y1_TLS_ADD 121 /* Y1 pipe "addi" for TLS GD/IE */ + +#define R_TILEGX_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ +#define R_TILEGX_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ + +#define R_TILEGX_NUM 130 + +/* RISC-V ELF Flags */ +#define EF_RISCV_RVC 0x0001 +#define EF_RISCV_FLOAT_ABI 0x0006 +#define EF_RISCV_FLOAT_ABI_SOFT 0x0000 +#define EF_RISCV_FLOAT_ABI_SINGLE 0x0002 +#define EF_RISCV_FLOAT_ABI_DOUBLE 0x0004 +#define EF_RISCV_FLOAT_ABI_QUAD 0x0006 + +/* RISC-V relocations. */ +#define R_RISCV_NONE 0 +#define R_RISCV_32 1 +#define R_RISCV_64 2 +#define R_RISCV_RELATIVE 3 +#define R_RISCV_COPY 4 +#define R_RISCV_JUMP_SLOT 5 +#define R_RISCV_TLS_DTPMOD32 6 +#define R_RISCV_TLS_DTPMOD64 7 +#define R_RISCV_TLS_DTPREL32 8 +#define R_RISCV_TLS_DTPREL64 9 +#define R_RISCV_TLS_TPREL32 10 +#define R_RISCV_TLS_TPREL64 11 +#define R_RISCV_BRANCH 16 +#define R_RISCV_JAL 17 +#define R_RISCV_CALL 18 +#define R_RISCV_CALL_PLT 19 +#define R_RISCV_GOT_HI20 20 +#define R_RISCV_TLS_GOT_HI20 21 +#define R_RISCV_TLS_GD_HI20 22 +#define R_RISCV_PCREL_HI20 23 +#define R_RISCV_PCREL_LO12_I 24 +#define R_RISCV_PCREL_LO12_S 25 +#define R_RISCV_HI20 26 +#define R_RISCV_LO12_I 27 +#define R_RISCV_LO12_S 28 +#define R_RISCV_TPREL_HI20 29 +#define R_RISCV_TPREL_LO12_I 30 +#define R_RISCV_TPREL_LO12_S 31 +#define R_RISCV_TPREL_ADD 32 +#define R_RISCV_ADD8 33 +#define R_RISCV_ADD16 34 +#define R_RISCV_ADD32 35 +#define R_RISCV_ADD64 36 +#define R_RISCV_SUB8 37 +#define R_RISCV_SUB16 38 +#define R_RISCV_SUB32 39 +#define R_RISCV_SUB64 40 +#define R_RISCV_GNU_VTINHERIT 41 +#define R_RISCV_GNU_VTENTRY 42 +#define R_RISCV_ALIGN 43 +#define R_RISCV_RVC_BRANCH 44 +#define R_RISCV_RVC_JUMP 45 +#define R_RISCV_RVC_LUI 46 +#define R_RISCV_GPREL_I 47 +#define R_RISCV_GPREL_S 48 +#define R_RISCV_TPREL_I 49 +#define R_RISCV_TPREL_S 50 +#define R_RISCV_RELAX 51 +#define R_RISCV_SUB6 52 +#define R_RISCV_SET6 53 +#define R_RISCV_SET8 54 +#define R_RISCV_SET16 55 +#define R_RISCV_SET32 56 +#define R_RISCV_32_PCREL 57 +#define R_RISCV_IRELATIVE 58 +#define R_RISCV_PLT32 59 +#define R_RISCV_SET_ULEB128 60 +#define R_RISCV_SUB_ULEB128 61 + +#define R_RISCV_NUM 62 + + +#endif /* elf.h */ diff --git a/programs/src/tcc/i386-asm.c b/programs/src/tcc/i386-asm.c new file mode 100644 index 0000000..64e44ce --- /dev/null +++ b/programs/src/tcc/i386-asm.c @@ -0,0 +1,1757 @@ +/* + * i386 specific functions for TCC assembler + * + * Copyright (c) 2001, 2002 Fabrice Bellard + * Copyright (c) 2009 Frédéric Feret (x86_64 support) + * + * This 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 of the License, or (at your option) any later version. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define USING_GLOBALS +#include "tcc.h" + +#define MAX_OPERANDS 3 + +#define TOK_ASM_first TOK_ASM_clc +#define TOK_ASM_last TOK_ASM_emms +#define TOK_ASM_alllast TOK_ASM_subps + +#define OPC_B 0x01 /* only used with OPC_WL */ +#define OPC_WL 0x02 /* accepts w, l or no suffix */ +#define OPC_BWL (OPC_B | OPC_WL) /* accepts b, w, l or no suffix */ +#define OPC_REG 0x04 /* register is added to opcode */ +#define OPC_MODRM 0x08 /* modrm encoding */ + +#define OPCT_MASK 0x70 +#define OPC_FWAIT 0x10 /* add fwait opcode */ +#define OPC_SHIFT 0x20 /* shift opcodes */ +#define OPC_ARITH 0x30 /* arithmetic opcodes */ +#define OPC_FARITH 0x40 /* FPU arithmetic opcodes */ +#define OPC_TEST 0x50 /* test opcodes */ +#define OPC_0F01 0x60 /* 0x0f01XX (group 7, XX is 2nd opcode, + no operands and unstructured mod/rm) */ +#define OPCT_IS(v,i) (((v) & OPCT_MASK) == (i)) + +#define OPC_0F 0x100 /* Is secondary map (0x0f prefix) */ +#define OPC_48 0x200 /* Always has REX prefix */ +#ifdef TCC_TARGET_X86_64 +# define OPC_WLQ 0x1000 /* accepts w, l, q or no suffix */ +# define OPC_BWLQ (OPC_B | OPC_WLQ) /* accepts b, w, l, q or no suffix */ +# define OPC_WLX OPC_WLQ +# define OPC_BWLX OPC_BWLQ +#else +# define OPC_WLX OPC_WL +# define OPC_BWLX OPC_BWL +#endif + +#define OPC_GROUP_SHIFT 13 + +/* in order to compress the operand type, we use specific operands and + we or only with EA */ +enum { + OPT_REG8=0, /* warning: value is hardcoded from TOK_ASM_xxx */ + OPT_REG16, /* warning: value is hardcoded from TOK_ASM_xxx */ + OPT_REG32, /* warning: value is hardcoded from TOK_ASM_xxx */ +#ifdef TCC_TARGET_X86_64 + OPT_REG64, /* warning: value is hardcoded from TOK_ASM_xxx */ +#endif + OPT_MMX, /* warning: value is hardcoded from TOK_ASM_xxx */ + OPT_SSE, /* warning: value is hardcoded from TOK_ASM_xxx */ + OPT_CR, /* warning: value is hardcoded from TOK_ASM_xxx */ + OPT_TR, /* warning: value is hardcoded from TOK_ASM_xxx */ + OPT_DB, /* warning: value is hardcoded from TOK_ASM_xxx */ + OPT_SEG, + OPT_ST, +#ifdef TCC_TARGET_X86_64 + OPT_REG8_LOW, /* %spl,%bpl,%sil,%dil, encoded like ah,ch,dh,bh, but + with REX prefix, not used in insn templates */ +#endif + OPT_IM8, + OPT_IM8S, + OPT_IM16, + OPT_IM32, +#ifdef TCC_TARGET_X86_64 + OPT_IM64, +#endif + OPT_EAX, /* %al, %ax, %eax or %rax register */ + OPT_ST0, /* %st(0) register */ + OPT_CL, /* %cl register */ + OPT_DX, /* %dx register */ + OPT_ADDR, /* OP_EA with only offset */ + OPT_INDIR, /* *(expr) */ + /* composite types */ + OPT_COMPOSITE_FIRST, + OPT_IM, /* IM8 | IM16 | IM32 */ + OPT_REG, /* REG8 | REG16 | REG32 | REG64 */ + OPT_REGW, /* REG16 | REG32 | REG64 */ + OPT_IMW, /* IM16 | IM32 */ + OPT_MMXSSE, /* MMX | SSE */ + OPT_DISP, /* Like OPT_ADDR, but emitted as displacement (for jumps) */ + OPT_DISP8, /* Like OPT_ADDR, but only 8bit (short jumps) */ + /* can be ored with any OPT_xxx */ + OPT_EA = 0x80 +}; + +#define OP_REG8 (1 << OPT_REG8) +#define OP_REG16 (1 << OPT_REG16) +#define OP_REG32 (1 << OPT_REG32) +#define OP_MMX (1 << OPT_MMX) +#define OP_SSE (1 << OPT_SSE) +#define OP_CR (1 << OPT_CR) +#define OP_TR (1 << OPT_TR) +#define OP_DB (1 << OPT_DB) +#define OP_SEG (1 << OPT_SEG) +#define OP_ST (1 << OPT_ST) +#define OP_IM8 (1 << OPT_IM8) +#define OP_IM8S (1 << OPT_IM8S) +#define OP_IM16 (1 << OPT_IM16) +#define OP_IM32 (1 << OPT_IM32) +#define OP_EAX (1 << OPT_EAX) +#define OP_ST0 (1 << OPT_ST0) +#define OP_CL (1 << OPT_CL) +#define OP_DX (1 << OPT_DX) +#define OP_ADDR (1 << OPT_ADDR) +#define OP_INDIR (1 << OPT_INDIR) +#ifdef TCC_TARGET_X86_64 +# define OP_REG64 (1 << OPT_REG64) +# define OP_REG8_LOW (1 << OPT_REG8_LOW) +# define OP_IM64 (1 << OPT_IM64) +# define OP_EA32 (OP_EA << 1) +#else +# define OP_REG64 0 +# define OP_REG8_LOW 0 +# define OP_IM64 0 +# define OP_EA32 0 +#endif + +#define OP_EA 0x40000000u +#define OP_REG (OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64) + +#ifdef TCC_TARGET_X86_64 +# define TREG_XAX TREG_RAX +# define TREG_XCX TREG_RCX +# define TREG_XDX TREG_RDX +# define TOK_ASM_xax TOK_ASM_rax +#else +# define TREG_XAX TREG_EAX +# define TREG_XCX TREG_ECX +# define TREG_XDX TREG_EDX +# define TOK_ASM_xax TOK_ASM_eax +#endif + +typedef struct ASMInstr { + uint16_t sym; + uint16_t opcode; + uint16_t instr_type; + uint8_t nb_ops; + uint8_t op_type[MAX_OPERANDS]; /* see OP_xxx */ +} ASMInstr; + +typedef struct Operand { + uint32_t type; + int8_t reg; /* register, -1 if none */ + int8_t reg2; /* second register, -1 if none */ + uint8_t shift; + ExprValue e; +} Operand; + +static const uint8_t reg_to_size[9] = { +/* + [OP_REG8] = 0, + [OP_REG16] = 1, + [OP_REG32] = 2, +#ifdef TCC_TARGET_X86_64 + [OP_REG64] = 3, +#endif +*/ + 0, 0, 1, 0, 2, 0, 0, 0, 3 +}; + +#define NB_TEST_OPCODES 30 + +static const uint8_t test_bits[NB_TEST_OPCODES] = { + 0x00, /* o */ + 0x01, /* no */ + 0x02, /* b */ + 0x02, /* c */ + 0x02, /* nae */ + 0x03, /* nb */ + 0x03, /* nc */ + 0x03, /* ae */ + 0x04, /* e */ + 0x04, /* z */ + 0x05, /* ne */ + 0x05, /* nz */ + 0x06, /* be */ + 0x06, /* na */ + 0x07, /* nbe */ + 0x07, /* a */ + 0x08, /* s */ + 0x09, /* ns */ + 0x0a, /* p */ + 0x0a, /* pe */ + 0x0b, /* np */ + 0x0b, /* po */ + 0x0c, /* l */ + 0x0c, /* nge */ + 0x0d, /* nl */ + 0x0d, /* ge */ + 0x0e, /* le */ + 0x0e, /* ng */ + 0x0f, /* nle */ + 0x0f, /* g */ +}; + +static const uint8_t segment_prefixes[] = { + 0x26, /* es */ + 0x2e, /* cs */ + 0x36, /* ss */ + 0x3e, /* ds */ + 0x64, /* fs */ + 0x65 /* gs */ +}; + +static const ASMInstr asm_instrs[] = { +#define ALT(x) x +/* This removes a 0x0f in the second byte */ +#define O(o) ((uint64_t) ((((o) & 0xff00) == 0x0f00) ? ((((o) >> 8) & ~0xff) | ((o) & 0xff)) : (o))) +/* This constructs instr_type from opcode, type and group. */ +#define T(o,i,g) ((i) | ((g) << OPC_GROUP_SHIFT) | ((((o) & 0xff00) == 0x0f00) ? OPC_0F : 0)) +#define DEF_ASM_OP0(name, opcode) +#define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 0, { 0 } }, +#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 1, { op0 }}, +#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 2, { op0, op1 }}, +#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 3, { op0, op1, op2 }}, +#ifdef TCC_TARGET_X86_64 +# include "x86_64-asm.h" +#else +# include "i386-asm.h" +#endif + /* last operation */ + { 0, }, +}; + +static const uint16_t op0_codes[] = { +#define ALT(x) +#define DEF_ASM_OP0(x, opcode) opcode, +#define DEF_ASM_OP0L(name, opcode, group, instr_type) +#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) +#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) +#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) +#ifdef TCC_TARGET_X86_64 +# include "x86_64-asm.h" +#else +# include "i386-asm.h" +#endif +}; + +static inline int get_reg_shift(TCCState *s1) +{ + int shift, v; + v = asm_int_expr(s1); + switch(v) { + case 1: + shift = 0; + break; + case 2: + shift = 1; + break; + case 4: + shift = 2; + break; + case 8: + shift = 3; + break; + default: + expect("1, 2, 4 or 8 constant"); + shift = 0; + break; + } + return shift; +} + +#ifdef TCC_TARGET_X86_64 +static int asm_parse_numeric_reg(int t, unsigned int *type) +{ + int reg = -1; + if (t >= TOK_IDENT && t < tok_ident) { + const char *s = table_ident[t - TOK_IDENT]->str; + char c; + *type = OP_REG64; + if (*s == 'c') { + s++; + *type = OP_CR; + } + if (*s++ != 'r') + return -1; + /* Don't allow leading '0'. */ + if ((c = *s++) >= '1' && c <= '9') + reg = c - '0'; + else + return -1; + if ((c = *s) >= '0' && c <= '5') + s++, reg = reg * 10 + c - '0'; + if (reg > 15) + return -1; + if ((c = *s) == 0) + ; + else if (*type != OP_REG64) + return -1; + else if (c == 'b' && !s[1]) + *type = OP_REG8; + else if (c == 'w' && !s[1]) + *type = OP_REG16; + else if (c == 'd' && !s[1]) + *type = OP_REG32; + else + return -1; + } + return reg; +} +#endif + +static int asm_parse_reg(unsigned int *type) +{ + int reg = 0; + *type = 0; + if (tok != '%') + goto error_32; + next(); + if (tok >= TOK_ASM_eax && tok <= TOK_ASM_edi) { + reg = tok - TOK_ASM_eax; + *type = OP_REG32; +#ifdef TCC_TARGET_X86_64 + } else if (tok >= TOK_ASM_rax && tok <= TOK_ASM_rdi) { + reg = tok - TOK_ASM_rax; + *type = OP_REG64; + } else if (tok == TOK_ASM_rip) { + reg = -2; /* Probably should use different escape code. */ + *type = OP_REG64; + } else if ((reg = asm_parse_numeric_reg(tok, type)) >= 0 + && (*type == OP_REG32 || *type == OP_REG64)) { + ; +#endif + } else { + error_32: + expect("register"); + } + next(); + return reg; +} + +static void parse_operand(TCCState *s1, Operand *op) +{ + ExprValue e; + int reg, indir; + const char *p; + + indir = 0; + if (tok == '*') { + next(); + indir = OP_INDIR; + } + + if (tok == '%') { + next(); + if (tok >= TOK_ASM_al && tok <= TOK_ASM_db7) { + reg = tok - TOK_ASM_al; + op->type = 1 << (reg >> 3); /* WARNING: do not change constant order */ + op->reg = reg & 7; + if ((op->type & OP_REG) && op->reg == TREG_XAX) + op->type |= OP_EAX; + else if (op->type == OP_REG8 && op->reg == TREG_XCX) + op->type |= OP_CL; + else if (op->type == OP_REG16 && op->reg == TREG_XDX) + op->type |= OP_DX; + } else if (tok >= TOK_ASM_dr0 && tok <= TOK_ASM_dr7) { + op->type = OP_DB; + op->reg = tok - TOK_ASM_dr0; + } else if (tok >= TOK_ASM_es && tok <= TOK_ASM_gs) { + op->type = OP_SEG; + op->reg = tok - TOK_ASM_es; + } else if (tok == TOK_ASM_st) { + op->type = OP_ST; + op->reg = 0; + next(); + if (tok == '(') { + next(); + if (tok != TOK_PPNUM) + goto reg_error; + p = tokc.str.data; + reg = p[0] - '0'; + if ((unsigned)reg >= 8 || p[1] != '\0') + goto reg_error; + op->reg = reg; + next(); + skip(')'); + } + if (op->reg == 0) + op->type |= OP_ST0; + goto no_skip; +#ifdef TCC_TARGET_X86_64 + } else if (tok >= TOK_ASM_spl && tok <= TOK_ASM_dil) { + op->type = OP_REG8 | OP_REG8_LOW; + op->reg = 4 + tok - TOK_ASM_spl; + } else if ((op->reg = asm_parse_numeric_reg(tok, &op->type)) >= 0) { + ; +#endif + } else { + reg_error: + tcc_error("unknown register %%%s", get_tok_str(tok, &tokc)); + } + next(); + no_skip: ; + } else if (tok == '$') { + /* constant value */ + next(); + asm_expr(s1, &e); + op->type = OP_IM32; + op->e = e; + if (!op->e.sym) { + if (op->e.v == (uint8_t)op->e.v) + op->type |= OP_IM8; + if (op->e.v == (int8_t)op->e.v) + op->type |= OP_IM8S; + if (op->e.v == (uint16_t)op->e.v) + op->type |= OP_IM16; +#ifdef TCC_TARGET_X86_64 + if (op->e.v != (int32_t)op->e.v && op->e.v != (uint32_t)op->e.v) + op->type = OP_IM64; +#endif + } + } else { + /* address(reg,reg2,shift) with all variants */ + op->type = OP_EA; + op->reg = -1; + op->reg2 = -1; + op->shift = 0; + if (tok != '(') { + asm_expr(s1, &e); + op->e = e; + } else { + next(); + if (tok == '%') { + unget_tok('('); + op->e.v = 0; + op->e.sym = NULL; + } else { + /* bracketed offset expression */ + asm_expr(s1, &e); + if (tok != ')') + expect(")"); + next(); + op->e.v = e.v; + op->e.sym = e.sym; + } + op->e.pcrel = 0; + } + if (tok == '(') { + unsigned int type = 0; + next(); + if (tok != ',') { + op->reg = asm_parse_reg(&type); + } + if (tok == ',') { + next(); + if (tok != ',') { + op->reg2 = asm_parse_reg(&type); + } + if (tok == ',') { + next(); + op->shift = get_reg_shift(s1); + } + } + if (type & OP_REG32) + op->type |= OP_EA32; + skip(')'); + } + if (op->reg == -1 && op->reg2 == -1) + op->type |= OP_ADDR; + } + op->type |= indir; +} + +/* XXX: unify with C code output ? */ +ST_FUNC void gen_expr32(ExprValue *pe) +{ + if (pe->pcrel) + /* If PC-relative, always set VT_SYM, even without symbol, + so as to force a relocation to be emitted. */ + gen_addrpc32(VT_SYM, pe->sym, pe->v + (ind + 4)); + else + gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v); +} + +#ifdef TCC_TARGET_X86_64 +ST_FUNC void gen_expr64(ExprValue *pe) +{ + gen_addr64(pe->sym ? VT_SYM : 0, pe->sym, pe->v); +} +#endif + +/* XXX: unify with C code output ? */ +static void gen_disp32(ExprValue *pe) +{ + Sym *sym = pe->sym; + ElfSym *esym = elfsym(sym); + if (esym && esym->st_shndx == cur_text_section->sh_num) { + /* same section: we can output an absolute value. Note + that the TCC compiler behaves differently here because + it always outputs a relocation to ease (future) code + elimination in the linker */ + gen_le32(pe->v + esym->st_value - ind - 4); + } else { + if (sym && sym->type.t == VT_VOID) { + sym->type.t = VT_FUNC; + sym->type.ref = NULL; + } +#ifdef TCC_TARGET_X86_64 + greloca(cur_text_section, sym, ind, R_X86_64_PLT32, pe->v - 4); + gen_le32(0); +#else + gen_addrpc32(VT_SYM, sym, pe->v); +#endif + + } +} + +/* generate the modrm operand */ +static inline int asm_modrm(int reg, Operand *op) +{ + int mod, reg1, reg2, sib_reg1; + + if (op->type & (OP_REG | OP_MMX | OP_SSE)) { + g(0xc0 + (reg << 3) + op->reg); + } else if (op->reg == -1 && op->reg2 == -1) { + /* displacement only */ +#ifdef TCC_TARGET_X86_64 + g(0x04 + (reg << 3)); + g(0x25); +#else + g(0x05 + (reg << 3)); +#endif + gen_expr32(&op->e); +#ifdef TCC_TARGET_X86_64 + } else if (op->reg == -2) { + ExprValue *pe = &op->e; + g(0x05 + (reg << 3)); + gen_addrpc32(pe->sym ? VT_SYM : 0, pe->sym, pe->v); + return ind; +#endif + } else { + sib_reg1 = op->reg; + /* fist compute displacement encoding */ + if (sib_reg1 == -1) { + sib_reg1 = 5; + mod = 0x00; + } else if (op->e.v == 0 && !op->e.sym && op->reg != 5) { + mod = 0x00; + } else if (op->e.v == (int8_t)op->e.v && !op->e.sym) { + mod = 0x40; + } else { + mod = 0x80; + } + /* compute if sib byte needed */ + reg1 = op->reg; + if (op->reg2 != -1) + reg1 = 4; + g(mod + (reg << 3) + reg1); + if (reg1 == 4) { + /* add sib byte */ + reg2 = op->reg2; + if (reg2 == -1) + reg2 = 4; /* indicate no index */ + g((op->shift << 6) + (reg2 << 3) + sib_reg1); + } + /* add offset */ + if (mod == 0x40) { + g(op->e.v); + } else if (mod == 0x80 || op->reg == -1) { + gen_expr32(&op->e); + } + } + return 0; +} + +#ifdef TCC_TARGET_X86_64 +#define REX_W 0x48 +#define REX_R 0x44 +#define REX_X 0x42 +#define REX_B 0x41 + +static void asm_rex(int width64, Operand *ops, int nb_ops, int *op_type, + int regi, int rmi) +{ + unsigned char rex = width64 ? 0x48 : 0; + int saw_high_8bit = 0; + int i; + if (rmi == -1) { + /* No mod/rm byte, but we might have a register op nevertheless + (we will add it to the opcode later). */ + for(i = 0; i < nb_ops; i++) { + if (op_type[i] & (OP_REG | OP_ST)) { + if (ops[i].reg >= 8) { + rex |= REX_B; + ops[i].reg -= 8; + } else if (ops[i].type & OP_REG8_LOW) + rex |= 0x40; + else if (ops[i].type & OP_REG8 && ops[i].reg >= 4) + /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */ + saw_high_8bit = ops[i].reg; + break; + } + } + } else { + if (regi != -1) { + if (ops[regi].reg >= 8) { + rex |= REX_R; + ops[regi].reg -= 8; + } else if (ops[regi].type & OP_REG8_LOW) + rex |= 0x40; + else if (ops[regi].type & OP_REG8 && ops[regi].reg >= 4) + /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */ + saw_high_8bit = ops[regi].reg; + } + if (ops[rmi].type & (OP_REG | OP_MMX | OP_SSE | OP_CR | OP_EA)) { + if (ops[rmi].reg >= 8) { + rex |= REX_B; + ops[rmi].reg -= 8; + } else if (ops[rmi].type & OP_REG8_LOW) + rex |= 0x40; + else if (ops[rmi].type & OP_REG8 && ops[rmi].reg >= 4) + /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */ + saw_high_8bit = ops[rmi].reg; + } + if (ops[rmi].type & OP_EA && ops[rmi].reg2 >= 8) { + rex |= REX_X; + ops[rmi].reg2 -= 8; + } + } + if (rex) { + if (saw_high_8bit) + tcc_error("can't encode register %%%ch when REX prefix is required", + "acdb"[saw_high_8bit-4]); + g(rex); + } +} +#endif + + +static void maybe_print_stats (void) +{ + static int already; + + if (0 && !already) + /* print stats about opcodes */ + { + const struct ASMInstr *pa; + int freq[4]; + int op_vals[500]; + int nb_op_vals, i, j; + + already = 1; + nb_op_vals = 0; + memset(freq, 0, sizeof(freq)); + for(pa = asm_instrs; pa->sym != 0; pa++) { + freq[pa->nb_ops]++; + //for(i=0;inb_ops;i++) { + for(j=0;jop_type[i] == op_vals[j]) + if (pa->instr_type == op_vals[j]) + goto found; + } + //op_vals[nb_op_vals++] = pa->op_type[i]; + op_vals[nb_op_vals++] = pa->instr_type; + found: ; + //} + } + for(i=0;i= TOK_ASM_wait && opcode <= TOK_ASM_repnz) + unget_tok(';'); + + /* get operands */ + pop = ops; + nb_ops = 0; + seg_prefix = 0; + alltypes = 0; + for(;;) { + if (tok == ';' || tok == TOK_LINEFEED) + break; + if (nb_ops >= MAX_OPERANDS) { + tcc_error("incorrect number of operands"); + } + parse_operand(s1, pop); + if (tok == ':') { + if (!(pop->type & OP_SEG) || seg_prefix) + tcc_error("incorrect prefix"); + seg_prefix = segment_prefixes[pop->reg]; + next(); + parse_operand(s1, pop); + if (!(pop->type & OP_EA)) { + tcc_error("segment prefix must be followed by memory reference"); + } + } + pop++; + nb_ops++; + if (tok != ',') + break; + next(); + } + + s = 0; /* avoid warning */ + +again: + /* optimize matching by using a lookup table (no hashing is needed + !) */ + for(pa = asm_instrs; pa->sym != 0; pa++) { + int it = pa->instr_type & OPCT_MASK; + s = 0; + if (it == OPC_FARITH) { + v = opcode - pa->sym; + if (!((unsigned)v < 8 * 6 && (v % 6) == 0)) + continue; + } else if (it == OPC_ARITH) { + if (!(opcode >= pa->sym && opcode < pa->sym + 8*NBWLX)) + continue; + s = (opcode - pa->sym) % NBWLX; + if ((pa->instr_type & OPC_BWLX) == OPC_WLX) + { + /* We need to reject the xxxb opcodes that we accepted above. + Note that pa->sym for WLX opcodes is the 'w' token, + to get the 'b' token subtract one. */ + if (((opcode - pa->sym + 1) % NBWLX) == 0) + continue; + s++; + } + } else if (it == OPC_SHIFT) { + if (!(opcode >= pa->sym && opcode < pa->sym + 7*NBWLX)) + continue; + s = (opcode - pa->sym) % NBWLX; + } else if (it == OPC_TEST) { + if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES)) + continue; + /* cmovxx is a test opcode but accepts multiple sizes. + The suffixes aren't encoded in the table, instead we + simply force size autodetection always and deal with suffixed + variants below when we don't find e.g. "cmovzl". */ + if (pa->instr_type & OPC_WLX) + s = NBWLX - 1; + } else if (pa->instr_type & OPC_B) { +#ifdef TCC_TARGET_X86_64 + /* Some instructions don't have the full size but only + bwl form. insb e.g. */ + if ((pa->instr_type & OPC_WLQ) != OPC_WLQ + && !(opcode >= pa->sym && opcode < pa->sym + NBWLX-1)) + continue; +#endif + if (!(opcode >= pa->sym && opcode < pa->sym + NBWLX)) + continue; + s = opcode - pa->sym; + } else if (pa->instr_type & OPC_WLX) { + if (!(opcode >= pa->sym && opcode < pa->sym + NBWLX-1)) + continue; + s = opcode - pa->sym + 1; + } else { + if (pa->sym != opcode) + continue; + } + if (pa->nb_ops != nb_ops) + continue; +#ifdef TCC_TARGET_X86_64 + /* Special case for moves. Selecting the IM64->REG64 form + should only be done if we really have an >32bit imm64, and that + is hardcoded. Ignore it here. */ + if (pa->opcode == 0xb0 && ops[0].type != OP_IM64 + && (ops[1].type & OP_REG) == OP_REG64 + && !(pa->instr_type & OPC_0F)) + continue; +#endif + /* now decode and check each operand */ + alltypes = 0; + for(i = 0; i < nb_ops; i++) { + int op1, op2; + op1 = pa->op_type[i]; + op2 = op1 & 0x1f; + switch(op2) { + case OPT_IM: + v = OP_IM8 | OP_IM16 | OP_IM32; + break; + case OPT_REG: + v = OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64; + break; + case OPT_REGW: + v = OP_REG16 | OP_REG32 | OP_REG64; + break; + case OPT_IMW: + v = OP_IM16 | OP_IM32; + break; + case OPT_MMXSSE: + v = OP_MMX | OP_SSE; + break; + case OPT_DISP: + case OPT_DISP8: + v = OP_ADDR; + break; + default: + v = 1 << op2; + break; + } + if (op1 & OPT_EA) + v |= OP_EA; + op_type[i] = v; + if ((ops[i].type & v) == 0) + goto next; + alltypes |= ops[i].type; + } + (void)alltypes; /* maybe unused */ + /* all is matching ! */ + break; + next: ; + } + if (pa->sym == 0) { + if (opcode >= TOK_ASM_first && opcode <= TOK_ASM_last) { + int b; + b = op0_codes[opcode - TOK_ASM_first]; + if (b & 0xff00) + g(b >> 8); + g(b); + return; + } else if (opcode <= TOK_ASM_alllast) { + tcc_error("bad operand with opcode '%s'", + get_tok_str(opcode, NULL)); + } else { + /* Special case for cmovcc, we accept size suffixes but ignore + them, but we don't want them to blow up our tables. */ + TokenSym *ts = table_ident[opcode - TOK_IDENT]; + if (ts->len >= 6 + && strchr("wlq", ts->str[ts->len-1]) + && !memcmp(ts->str, "cmov", 4)) { + opcode = tok_alloc(ts->str, ts->len-1)->tok; + goto again; + } + tcc_error("unknown opcode '%s'", ts->str); + } + } + /* if the size is unknown, then evaluate it (OPC_B or OPC_WL case) */ + autosize = NBWLX-1; +#ifdef TCC_TARGET_X86_64 + /* XXX the autosize should rather be zero, to not have to adjust this + all the time. */ + if ((pa->instr_type & OPC_BWLQ) == OPC_B) + autosize = NBWLX-2; +#endif + if (s == autosize) { + /* Check for register operands providing hints about the size. + Start from the end, i.e. destination operands. This matters + only for opcodes accepting different sized registers, lar and lsl + are such opcodes. */ + for(i = nb_ops - 1; s == autosize && i >= 0; i--) { + if ((ops[i].type & OP_REG) && !(op_type[i] & (OP_CL | OP_DX))) + s = reg_to_size[ops[i].type & OP_REG]; + } + if (s == autosize) { + if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) && + (ops[0].type & (OP_SEG | OP_IM8S | OP_IM32))) + s = 2; + else if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) && + (ops[0].type & OP_EA)) + s = NBWLX - 2; + else + tcc_error("cannot infer opcode suffix"); + } + } + +#ifdef TCC_TARGET_X86_64 + rex64 = 0; + if (pa->instr_type & OPC_48) + rex64 = 1; + else if (s == 3 || (alltypes & OP_REG64)) { + /* generate REX prefix */ + int default64 = 0; + for(i = 0; i < nb_ops; i++) { + if (op_type[i] == OP_REG64 && pa->opcode != 0xb8) { + /* If only 64bit regs are accepted in one operand + this is a default64 instruction without need for + REX prefixes, except for movabs(0xb8). */ + default64 = 1; + break; + } + } + /* XXX find better encoding for the default64 instructions. */ + if (((opcode != TOK_ASM_push && opcode != TOK_ASM_pop + && opcode != TOK_ASM_pushw && opcode != TOK_ASM_pushl + && opcode != TOK_ASM_pushq && opcode != TOK_ASM_popw + && opcode != TOK_ASM_popl && opcode != TOK_ASM_popq + && opcode != TOK_ASM_call && opcode != TOK_ASM_jmp)) + && !default64) + rex64 = 1; + } +#endif + + /* now generates the operation */ + if (OPCT_IS(pa->instr_type, OPC_FWAIT)) + g(0x9b); + if (seg_prefix) + g(seg_prefix); +#ifdef TCC_TARGET_X86_64 + /* Generate addr32 prefix if needed */ + for(i = 0; i < nb_ops; i++) { + if (ops[i].type & OP_EA32) { + g(0x67); + break; + } + } +#endif + /* generate data16 prefix if needed */ + p66 = 0; + if (s == 1) + p66 = 1; + else { + /* accepting mmx+sse in all operands --> needs 0x66 to + switch to sse mode. Accepting only sse in an operand --> is + already SSE insn and needs 0x66/f2/f3 handling. */ + for (i = 0; i < nb_ops; i++) + if ((op_type[i] & (OP_MMX | OP_SSE)) == (OP_MMX | OP_SSE) + && ops[i].type & OP_SSE) + p66 = 1; + } + if (p66) + g(0x66); + + v = pa->opcode; + p = v >> 8; /* possibly prefix byte(s) */ + switch (p) { + case 0: break; /* no prefix */ + case 0x48: break; /* REX, handled elsewhere */ + case 0x66: + case 0x67: + case 0xf2: + case 0xf3: v = v & 0xff; g(p); break; + case 0xd4: case 0xd5: break; /* aam and aad, not prefix, but hardcoded immediate argument "10" */ + case 0xd8: case 0xd9: case 0xda: case 0xdb: /* x87, no normal prefix */ + case 0xdc: case 0xdd: case 0xde: case 0xdf: break; + default: tcc_error("bad prefix 0x%2x in opcode table", p); break; + } + if (pa->instr_type & OPC_0F) + v = ((v & ~0xff) << 8) | 0x0f00 | (v & 0xff); + if ((v == 0x69 || v == 0x6b) && nb_ops == 2) { + /* kludge for imul $im, %reg */ + nb_ops = 3; + ops[2] = ops[1]; + op_type[2] = op_type[1]; + } else if (v == 0xcd && ops[0].e.v == 3 && !ops[0].e.sym) { + v--; /* int $3 case */ + nb_ops = 0; + } else if ((v == 0x06 || v == 0x07)) { + if (ops[0].reg >= 4) { + /* push/pop %fs or %gs */ + v = 0x0fa0 + (v - 0x06) + ((ops[0].reg - 4) << 3); + } else { + v += ops[0].reg << 3; + } + nb_ops = 0; + } else if (v <= 0x05) { + /* arith case */ + v += ((opcode - TOK_ASM_addb) / NBWLX) << 3; + } else if ((pa->instr_type & (OPCT_MASK | OPC_MODRM)) == OPC_FARITH) { + /* fpu arith case */ + v += ((opcode - pa->sym) / 6) << 3; + } + + /* search which operand will be used for modrm */ + modrm_index = -1; + modreg_index = -1; + if (pa->instr_type & OPC_MODRM) { + if (!nb_ops) { + /* A modrm opcode without operands is a special case (e.g. mfence). + It has a group and acts as if there's an register operand 0 */ + i = 0; + ops[i].type = OP_REG; +#ifdef TCC_TARGET_X86_64 + if (pa->sym == TOK_ASM_endbr64) + ops[i].reg = 2; // dx + else if (pa->sym >= TOK_ASM_lfence && pa->sym <= TOK_ASM_sfence) + ops[i].reg = 0; // ax +#else + if (pa->sym == TOK_ASM_endbr32) + ops[i].reg = 3; // bx +#endif + else + tcc_error("bad MODR/M opcode without operands"); + goto modrm_found; + } + /* first look for an ea operand */ + for(i = 0;i < nb_ops; i++) { + if (op_type[i] & OP_EA) + goto modrm_found; + } + /* then if not found, a register or indirection (shift instructions) */ + for(i = 0;i < nb_ops; i++) { + if (op_type[i] & (OP_REG | OP_MMX | OP_SSE | OP_INDIR)) + goto modrm_found; + } +#ifdef ASM_DEBUG + tcc_error("bad op table"); +#endif + modrm_found: + modrm_index = i; + /* if a register is used in another operand then it is + used instead of group */ + for(i = 0;i < nb_ops; i++) { + int t = op_type[i]; + if (i != modrm_index && + (t & (OP_REG | OP_MMX | OP_SSE | OP_CR | OP_TR | OP_DB | OP_SEG))) { + modreg_index = i; + break; + } + } + } +#ifdef TCC_TARGET_X86_64 + asm_rex (rex64, ops, nb_ops, op_type, modreg_index, modrm_index); +#endif + + if (pa->instr_type & OPC_REG) { + /* mov $im, %reg case */ + if (v == 0xb0 && s >= 1) + v += 7; + for(i = 0; i < nb_ops; i++) { + if (op_type[i] & (OP_REG | OP_ST)) { + v += ops[i].reg; + break; + } + } + } + if (pa->instr_type & OPC_B) + v += s >= 1; + if (nb_ops == 1 && pa->op_type[0] == OPT_DISP8) { + ElfSym *esym; + int jmp_disp; + + /* see if we can really generate the jump with a byte offset */ + esym = elfsym(ops[0].e.sym); + if (!esym || esym->st_shndx != cur_text_section->sh_num) + goto no_short_jump; + jmp_disp = ops[0].e.v + esym->st_value - ind - 2 - (v >= 0xff); + if (jmp_disp == (int8_t)jmp_disp) { + /* OK to generate jump */ + ops[0].e.sym = 0; + ops[0].e.v = jmp_disp; + op_type[0] = OP_IM8S; + } else { + no_short_jump: + /* long jump will be allowed. need to modify the + opcode slightly */ + if (v == 0xeb) /* jmp */ + v = 0xe9; + else if (v == 0x70) /* jcc */ + v += 0x0f10; + else + tcc_error("invalid displacement"); + } + } + if (OPCT_IS(pa->instr_type, OPC_TEST)) + v += test_bits[opcode - pa->sym]; + else if (OPCT_IS(pa->instr_type, OPC_0F01)) + v |= 0x0f0100; + op1 = v >> 16; + if (op1) + g(op1); + op1 = (v >> 8) & 0xff; + if (op1) + g(op1); + g(v); + + if (OPCT_IS(pa->instr_type, OPC_SHIFT)) { + reg = (opcode - pa->sym) / NBWLX; + if (reg == 6) + reg = 7; + } else if (OPCT_IS(pa->instr_type, OPC_ARITH)) { + reg = (opcode - pa->sym) / NBWLX; + } else if (OPCT_IS(pa->instr_type, OPC_FARITH)) { + reg = (opcode - pa->sym) / 6; + } else { + reg = (pa->instr_type >> OPC_GROUP_SHIFT) & 7; + } + + pc = 0; + if (pa->instr_type & OPC_MODRM) { + /* if a register is used in another operand then it is + used instead of group */ + if (modreg_index >= 0) + reg = ops[modreg_index].reg; + pc = asm_modrm(reg, &ops[modrm_index]); + } + + /* emit constants */ +#ifndef TCC_TARGET_X86_64 + if (!(pa->instr_type & OPC_0F) + && (pa->opcode == 0x9a || pa->opcode == 0xea)) { + /* ljmp or lcall kludge */ + gen_expr32(&ops[1].e); + if (ops[0].e.sym) + tcc_error("cannot relocate"); + gen_le16(ops[0].e.v); + return; + } +#endif + for(i = 0;i < nb_ops; i++) { + v = op_type[i]; + if (v & (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64 | OP_IM8S | OP_ADDR)) { + /* if multiple sizes are given it means we must look + at the op size */ + if ((v | OP_IM8 | OP_IM64) == (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64)) { + if (s == 0) + v = OP_IM8; + else if (s == 1) + v = OP_IM16; + else if (s == 2 || (v & OP_IM64) == 0) + v = OP_IM32; + else + v = OP_IM64; + } + + if ((v & (OP_IM8 | OP_IM8S | OP_IM16)) && ops[i].e.sym) + tcc_error("cannot relocate"); + + if (v & (OP_IM8 | OP_IM8S)) { + g(ops[i].e.v); + } else if (v & OP_IM16) { + gen_le16(ops[i].e.v); +#ifdef TCC_TARGET_X86_64 + } else if (v & OP_IM64) { + gen_expr64(&ops[i].e); +#endif + } else if (pa->op_type[i] == OPT_DISP || pa->op_type[i] == OPT_DISP8) { + gen_disp32(&ops[i].e); + } else { + gen_expr32(&ops[i].e); + } + } + } + + /* after immediate operands, adjust pc-relative address */ + if (pc) + add32le(cur_text_section->data + pc - 4, pc - ind); +} + +/* return the constraint priority (we allocate first the lowest + numbered constraints) */ +static inline int constraint_priority(const char *str) +{ + int priority, c, pr; + + /* we take the lowest priority */ + priority = 0; + for(;;) { + c = *str; + if (c == '\0') + break; + str++; + switch(c) { + case 'A': + pr = 0; + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'S': + case 'D': + pr = 1; + break; + case 'q': + pr = 2; + break; + case 'r': + case 'R': + case 'p': + pr = 3; + break; + case 'N': + case 'M': + case 'I': + case 'e': + case 'i': + case 'm': + case 'g': + pr = 4; + break; + default: + tcc_error("unknown constraint '%c'", c); + pr = 0; + } + if (pr > priority) + priority = pr; + } + return priority; +} + +static const char *skip_constraint_modifiers(const char *p) +{ + while (*p == '=' || *p == '&' || *p == '+' || *p == '%') + p++; + return p; +} + +/* If t (a token) is of the form "%reg" or "reg" return the register number and + type, otherwise return -1. With GCC the % is optional, too. */ +ST_FUNC int asm_parse_regvar (int t) +{ + const char *s; + Operand op; + if (t < TOK_IDENT || (t & SYM_FIELD)) + return -1; + s = table_ident[t - TOK_IDENT]->str; + if (s[0] == '%') + ++s; + t = tok_alloc_const(s); + unget_tok(t); + /* Internally the % prefix is required. */ + unget_tok('%'); + parse_operand(tcc_state, &op); + /* Accept only integer regs for now. */ + if (op.type & OP_REG) + return op.reg; + else + return -1; +} + +#define REG_OUT_MASK 0x01 +#define REG_IN_MASK 0x02 + +#define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask) + +ST_FUNC void asm_compute_constraints(ASMOperand *operands, + int nb_operands, int nb_outputs, + const uint8_t *clobber_regs, + int *pout_reg) +{ + ASMOperand *op; + int sorted_op[MAX_ASM_OPERANDS]; + int i, j, k, p1, p2, tmp, reg, c, reg_mask; + const char *str; + uint8_t regs_allocated[NB_ASM_REGS]; + + /* init fields */ + for(i=0;iinput_index = -1; + op->ref_index = -1; + op->reg = -1; + op->is_memory = 0; + op->is_rw = 0; + } + /* compute constraint priority and evaluate references to output + constraints if input constraints */ + for(i=0;iconstraint; + str = skip_constraint_modifiers(str); + if (isnum(*str) || *str == '[') { + /* this is a reference to another constraint */ + k = find_constraint(operands, nb_operands, str, NULL); + if ((unsigned)k >= i || i < nb_outputs) + tcc_error("invalid reference in constraint %d ('%s')", + i, str); + op->ref_index = k; + if (operands[k].input_index >= 0) + tcc_error("cannot reference twice the same operand"); + operands[k].input_index = i; + op->priority = 5; + } else if ((op->vt->r & VT_VALMASK) == VT_LOCAL + && op->vt->sym + && (reg = op->vt->sym->r & VT_VALMASK) < VT_CONST) { + op->priority = 1; + op->reg = reg; + } else { + op->priority = constraint_priority(str); + } + } + + /* sort operands according to their priority */ + for(i=0;iconstraint; + /* no need to allocate references */ + if (op->ref_index >= 0) + continue; + /* select if register is used for output, input or both */ + if (op->input_index >= 0) { + reg_mask = REG_IN_MASK | REG_OUT_MASK; + } else if (j < nb_outputs) { + reg_mask = REG_OUT_MASK; + } else { + reg_mask = REG_IN_MASK; + } + if (op->reg >= 0) { + if (is_reg_allocated(op->reg)) + tcc_error("asm regvar requests register that's taken already"); + reg = op->reg; + } + try_next: + c = *str++; + switch(c) { + case '=': + goto try_next; + case '+': + op->is_rw = 1; + /* FALL THRU */ + case '&': + if (j >= nb_outputs) + tcc_error("'%c' modifier can only be applied to outputs", c); + reg_mask = REG_IN_MASK | REG_OUT_MASK; + goto try_next; + case 'A': + /* allocate both eax and edx */ + if (is_reg_allocated(TREG_XAX) || + is_reg_allocated(TREG_XDX)) + goto try_next; + op->is_llong = 1; + op->reg = TREG_XAX; + regs_allocated[TREG_XAX] |= reg_mask; + regs_allocated[TREG_XDX] |= reg_mask; + break; + case 'a': + reg = TREG_XAX; + goto alloc_reg; + case 'b': + reg = 3; + goto alloc_reg; + case 'c': + reg = TREG_XCX; + goto alloc_reg; + case 'd': + reg = TREG_XDX; + goto alloc_reg; + case 'S': + reg = 6; + goto alloc_reg; + case 'D': + reg = 7; + alloc_reg: + if (op->reg >= 0 && reg != op->reg) + goto try_next; + if (is_reg_allocated(reg)) + goto try_next; + goto reg_found; + case 'q': + /* eax, ebx, ecx or edx */ + if (op->reg >= 0) { + if ((reg = op->reg) < 4) + goto reg_found; + } else for(reg = 0; reg < 4; reg++) { + if (!is_reg_allocated(reg)) + goto reg_found; + } + goto try_next; + case 'r': + case 'R': + case 'p': /* A general address, for x86(64) any register is acceptable*/ + /* any general register */ + if ((reg = op->reg) >= 0) + goto reg_found; + else for(reg = 0; reg < NB_ASM_REGS; reg++) { + if (!is_reg_allocated(reg)) + goto reg_found; + } + goto try_next; + reg_found: + /* now we can reload in the register */ + op->is_llong = 0; + op->reg = reg; + regs_allocated[reg] |= reg_mask; + break; + case 'e': + case 'i': + if (!((op->vt->r & (VT_VALMASK | VT_LVAL)) == VT_CONST)) + goto try_next; + break; + case 'I': + case 'N': + case 'M': + if (!((op->vt->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST)) + goto try_next; + break; + case 'm': + case 'g': + /* nothing special to do because the operand is already in + memory, except if the pointer itself is stored in a + memory variable (VT_LLOCAL case) */ + /* XXX: fix constant case */ + /* if it is a reference to a memory zone, it must lie + in a register, so we reserve the register in the + input registers and a load will be generated + later */ + if (j < nb_outputs || c == 'm') { + if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) { + /* any general register */ + for(reg = 0; reg < NB_ASM_REGS; reg++) { + if (!(regs_allocated[reg] & REG_IN_MASK)) + goto reg_found1; + } + goto try_next; + reg_found1: + /* now we can reload in the register */ + regs_allocated[reg] |= REG_IN_MASK; + op->reg = reg; + op->is_memory = 1; + } + } + break; + default: + tcc_error("asm constraint %d ('%s') could not be satisfied", + j, op->constraint); + break; + } + /* if a reference is present for that operand, we assign it too */ + if (op->input_index >= 0) { + operands[op->input_index].reg = op->reg; + operands[op->input_index].is_llong = op->is_llong; + } + } + + /* compute out_reg. It is used to store outputs registers to memory + locations references by pointers (VT_LLOCAL case) */ + *pout_reg = -1; + for(i=0;ireg >= 0 && + (op->vt->r & VT_VALMASK) == VT_LLOCAL && + !op->is_memory) { + for(reg = 0; reg < NB_ASM_REGS; reg++) { + if (!(regs_allocated[reg] & REG_OUT_MASK)) + goto reg_found2; + } + tcc_error("could not find free output register for reloading"); + reg_found2: + *pout_reg = reg; + break; + } + } + + /* print sorted constraints */ +#ifdef ASM_DEBUG + for(i=0;iid ? get_tok_str(op->id, NULL) : "", + op->constraint, + op->vt->r, + op->reg); + } + if (*pout_reg >= 0) + printf("out_reg=%d\n", *pout_reg); +#endif +} + +ST_FUNC void subst_asm_operand(CString *add_str, + SValue *sv, int modifier) +{ + int r, reg, size, val; + + r = sv->r; + if ((r & VT_VALMASK) == VT_CONST) { + if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n' && + modifier != 'P') + cstr_ccat(add_str, '$'); + if (r & VT_SYM) { + const char *name = get_tok_str(sv->sym->v, NULL); + if (sv->sym->v >= SYM_FIRST_ANOM) { + /* In case of anonymous symbols ("L.42", used + for static data labels) we can't find them + in the C symbol table when later looking up + this name. So enter them now into the asm label + list when we still know the symbol. */ + get_asm_sym(tok_alloc_const(name), sv->sym); + } + if (tcc_state->leading_underscore) + cstr_ccat(add_str, '_'); + cstr_cat(add_str, name, -1); + if ((uint32_t)sv->c.i == 0) + goto no_offset; + cstr_ccat(add_str, '+'); + } + val = sv->c.i; + if (modifier == 'n') + val = -val; + cstr_printf(add_str, "%d", (int)sv->c.i); + no_offset:; +#ifdef TCC_TARGET_X86_64 + if (r & VT_LVAL) + cstr_cat(add_str, "(%rip)", -1); +#endif + } else if ((r & VT_VALMASK) == VT_LOCAL) { + cstr_printf(add_str, "%d(%%%s)", (int)sv->c.i, get_tok_str(TOK_ASM_xax + 5, NULL)); + } else if (r & VT_LVAL) { + reg = r & VT_VALMASK; + if (reg >= VT_CONST) + tcc_internal_error(""); + cstr_printf(add_str, "(%%%s)", get_tok_str(TOK_ASM_xax + reg, NULL)); + } else { + /* register case */ + reg = r & VT_VALMASK; + if (reg >= VT_CONST) + tcc_internal_error(""); + + /* choose register operand size */ + if ((sv->type.t & VT_BTYPE) == VT_BYTE || + (sv->type.t & VT_BTYPE) == VT_BOOL) + size = 1; + else if ((sv->type.t & VT_BTYPE) == VT_SHORT) + size = 2; +#ifdef TCC_TARGET_X86_64 + else if ((sv->type.t & VT_BTYPE) == VT_LLONG || + (sv->type.t & VT_BTYPE) == VT_PTR) + size = 8; +#endif + else + size = 4; + if (size == 1 && reg >= 4) + size = 4; + + if (modifier == 'b') { + if (reg >= 4) + tcc_error("cannot use byte register"); + size = 1; + } else if (modifier == 'h') { + if (reg >= 4) + tcc_error("cannot use byte register"); + size = -1; + } else if (modifier == 'w') { + size = 2; + } else if (modifier == 'k') { + size = 4; +#ifdef TCC_TARGET_X86_64 + } else if (modifier == 'q') { + size = 8; +#endif + } + + if (reg >= 8) { + cstr_printf(add_str, "%%r%d%c", reg, (size == 1) ? 'b' : ((size == 2) ? 'w' : ((size == 4) ? 'd' : ' '))); + return; + } + switch(size) { + case -1: + reg = TOK_ASM_ah + reg; + break; + case 1: + reg = TOK_ASM_al + reg; + break; + case 2: + reg = TOK_ASM_ax + reg; + break; + default: + reg = TOK_ASM_eax + reg; + break; +#ifdef TCC_TARGET_X86_64 + case 8: + reg = TOK_ASM_rax + reg; + break; +#endif + } + cstr_printf(add_str, "%%%s", get_tok_str(reg, NULL)); + } +} + +/* generate prolog and epilog code for asm statement */ +ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, + int nb_outputs, int is_output, + uint8_t *clobber_regs, + int out_reg) +{ + uint8_t regs_allocated[NB_ASM_REGS]; + ASMOperand *op; + int i, reg; + + /* Strictly speaking %Xbp and %Xsp should be included in the + call-preserved registers, but currently it doesn't matter. */ +#ifdef TCC_TARGET_X86_64 +#ifdef TCC_TARGET_PE + static const uint8_t reg_saved[] = { 3, 6, 7, 12, 13, 14, 15 }; +#else + static const uint8_t reg_saved[] = { 3, 12, 13, 14, 15 }; +#endif +#else + static const uint8_t reg_saved[] = { 3, 6, 7 }; +#endif + + /* mark all used registers */ + memcpy(regs_allocated, clobber_regs, sizeof(regs_allocated)); + for(i = 0; i < nb_operands;i++) { + op = &operands[i]; + if (op->reg >= 0) + regs_allocated[op->reg] = 1; + } + if (!is_output) { + /* generate reg save code */ + for(i = 0; i < sizeof(reg_saved)/sizeof(reg_saved[0]); i++) { + reg = reg_saved[i]; + if (regs_allocated[reg]) { + if (reg >= 8) + g(0x41), reg-=8; + g(0x50 + reg); + } + } + + /* generate load code */ + for(i = 0; i < nb_operands; i++) { + op = &operands[i]; + if (op->reg >= 0) { + if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && + op->is_memory) { + /* memory reference case (for both input and + output cases) */ + SValue sv; + sv = *op->vt; + sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL; + sv.type.t = VT_PTR; + load(op->reg, &sv); + } else if (i >= nb_outputs || op->is_rw) { + /* load value in register */ + load(op->reg, op->vt); + if (op->is_llong) { + SValue sv; + sv = *op->vt; + sv.c.i += 4; + load(TREG_XDX, &sv); + } + } + } + } + } else { + /* generate save code */ + for(i = 0 ; i < nb_outputs; i++) { + op = &operands[i]; + if (op->reg >= 0) { + if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) { + if (!op->is_memory) { + SValue sv; + sv = *op->vt; + sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL; + sv.type.t = VT_PTR; + load(out_reg, &sv); + + sv = *op->vt; + sv.r = (sv.r & ~VT_VALMASK) | out_reg; + store(op->reg, &sv); + } + } else { + store(op->reg, op->vt); + if (op->is_llong) { + SValue sv; + sv = *op->vt; + sv.c.i += 4; + store(TREG_XDX, &sv); + } + } + } + } + /* generate reg restore code */ + for(i = sizeof(reg_saved)/sizeof(reg_saved[0]) - 1; i >= 0; i--) { + reg = reg_saved[i]; + if (regs_allocated[reg]) { + if (reg >= 8) + g(0x41), reg-=8; + g(0x58 + reg); + } + } + } +} + +ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str) +{ + int reg; +#ifdef TCC_TARGET_X86_64 + unsigned int type; +#endif + + if (!strcmp(str, "memory") || + !strcmp(str, "cc") || + !strcmp(str, "flags")) + return; + reg = tok_alloc_const(str); + if (reg >= TOK_ASM_eax && reg <= TOK_ASM_edi) { + reg -= TOK_ASM_eax; + } else if (reg >= TOK_ASM_ax && reg <= TOK_ASM_di) { + reg -= TOK_ASM_ax; +#ifdef TCC_TARGET_X86_64 + } else if (reg >= TOK_ASM_rax && reg <= TOK_ASM_rdi) { + reg -= TOK_ASM_rax; + } else if ((reg = asm_parse_numeric_reg(reg, &type)) >= 0) { + ; +#endif + } else { + tcc_error("invalid clobber register '%s'", str); + } + clobber_regs[reg] = 1; +} diff --git a/programs/src/tcc/i386-asm.h b/programs/src/tcc/i386-asm.h new file mode 100644 index 0000000..107fd3d --- /dev/null +++ b/programs/src/tcc/i386-asm.h @@ -0,0 +1,490 @@ + DEF_ASM_OP0(clc, 0xf8) /* must be first OP0 */ + DEF_ASM_OP0(cld, 0xfc) + DEF_ASM_OP0(cli, 0xfa) + DEF_ASM_OP0(clts, 0x0f06) + DEF_ASM_OP0(cmc, 0xf5) + DEF_ASM_OP0(lahf, 0x9f) + DEF_ASM_OP0(sahf, 0x9e) + DEF_ASM_OP0(pusha, 0x60) + DEF_ASM_OP0(popa, 0x61) + DEF_ASM_OP0(pushfl, 0x9c) + DEF_ASM_OP0(popfl, 0x9d) + DEF_ASM_OP0(pushf, 0x9c) + DEF_ASM_OP0(popf, 0x9d) + DEF_ASM_OP0(stc, 0xf9) + DEF_ASM_OP0(std, 0xfd) + DEF_ASM_OP0(sti, 0xfb) + DEF_ASM_OP0(aaa, 0x37) + DEF_ASM_OP0(aas, 0x3f) + DEF_ASM_OP0(daa, 0x27) + DEF_ASM_OP0(das, 0x2f) + DEF_ASM_OP0(aad, 0xd50a) + DEF_ASM_OP0(aam, 0xd40a) + DEF_ASM_OP0(cbw, 0x6698) + DEF_ASM_OP0(cwd, 0x6699) + DEF_ASM_OP0(cwde, 0x98) + DEF_ASM_OP0(cdq, 0x99) + DEF_ASM_OP0(cbtw, 0x6698) + DEF_ASM_OP0(cwtl, 0x98) + DEF_ASM_OP0(cwtd, 0x6699) + DEF_ASM_OP0(cltd, 0x99) + DEF_ASM_OP0(int3, 0xcc) + DEF_ASM_OP0(into, 0xce) + DEF_ASM_OP0(iret, 0xcf) + DEF_ASM_OP0(rsm, 0x0faa) + DEF_ASM_OP0(hlt, 0xf4) + DEF_ASM_OP0(nop, 0x90) + DEF_ASM_OP0(pause, 0xf390) + DEF_ASM_OP0(xlat, 0xd7) + + /* Control-Flow Enforcement */ + DEF_ASM_OP0L(endbr32, 0xf30f1e, 7, OPC_MODRM) + + /* strings */ +ALT(DEF_ASM_OP0L(cmpsb, 0xa6, 0, OPC_BWLX)) +ALT(DEF_ASM_OP0L(scmpb, 0xa6, 0, OPC_BWLX)) + +ALT(DEF_ASM_OP0L(insb, 0x6c, 0, OPC_BWL)) +ALT(DEF_ASM_OP0L(outsb, 0x6e, 0, OPC_BWL)) + +ALT(DEF_ASM_OP0L(lodsb, 0xac, 0, OPC_BWLX)) +ALT(DEF_ASM_OP0L(slodb, 0xac, 0, OPC_BWLX)) + +ALT(DEF_ASM_OP0L(movsb, 0xa4, 0, OPC_BWLX)) +ALT(DEF_ASM_OP0L(smovb, 0xa4, 0, OPC_BWLX)) + +ALT(DEF_ASM_OP0L(scasb, 0xae, 0, OPC_BWLX)) +ALT(DEF_ASM_OP0L(sscab, 0xae, 0, OPC_BWLX)) + +ALT(DEF_ASM_OP0L(stosb, 0xaa, 0, OPC_BWLX)) +ALT(DEF_ASM_OP0L(sstob, 0xaa, 0, OPC_BWLX)) + + /* bits */ + +ALT(DEF_ASM_OP2(bsfw, 0x0fbc, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) +ALT(DEF_ASM_OP2(bsrw, 0x0fbd, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) + +ALT(DEF_ASM_OP2(btw, 0x0fa3, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA)) +ALT(DEF_ASM_OP2(btw, 0x0fba, 4, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) + +ALT(DEF_ASM_OP2(btsw, 0x0fab, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA)) +ALT(DEF_ASM_OP2(btsw, 0x0fba, 5, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) + +ALT(DEF_ASM_OP2(btrw, 0x0fb3, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA)) +ALT(DEF_ASM_OP2(btrw, 0x0fba, 6, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) + +ALT(DEF_ASM_OP2(btcw, 0x0fbb, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA)) +ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA)) + +ALT(DEF_ASM_OP2(popcntw, 0xf30fb8, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) + +ALT(DEF_ASM_OP2(tzcntw, 0xf30fbc, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) +ALT(DEF_ASM_OP2(lzcntw, 0xf30fbd, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) + + /* prefixes */ + DEF_ASM_OP0(wait, 0x9b) + DEF_ASM_OP0(fwait, 0x9b) + DEF_ASM_OP0(aword, 0x67) + DEF_ASM_OP0(addr16, 0x67) + ALT(DEF_ASM_OP0(word, 0x66)) + DEF_ASM_OP0(data16, 0x66) + DEF_ASM_OP0(lock, 0xf0) + DEF_ASM_OP0(rep, 0xf3) + DEF_ASM_OP0(repe, 0xf3) + DEF_ASM_OP0(repz, 0xf3) + DEF_ASM_OP0(repne, 0xf2) + DEF_ASM_OP0(repnz, 0xf2) + + DEF_ASM_OP0(invd, 0x0f08) + DEF_ASM_OP0(wbinvd, 0x0f09) + DEF_ASM_OP0(cpuid, 0x0fa2) + DEF_ASM_OP0(wrmsr, 0x0f30) + DEF_ASM_OP0(rdtsc, 0x0f31) + DEF_ASM_OP0(rdmsr, 0x0f32) + DEF_ASM_OP0(rdpmc, 0x0f33) + DEF_ASM_OP0(ud2, 0x0f0b) + + /* NOTE: we took the same order as gas opcode definition order */ +ALT(DEF_ASM_OP2(movb, 0xa0, 0, OPC_BWLX, OPT_ADDR, OPT_EAX)) +ALT(DEF_ASM_OP2(movb, 0xa2, 0, OPC_BWLX, OPT_EAX, OPT_ADDR)) +ALT(DEF_ASM_OP2(movb, 0x88, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) +ALT(DEF_ASM_OP2(movb, 0x8a, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG)) +ALT(DEF_ASM_OP2(movb, 0xb0, 0, OPC_REG | OPC_BWLX, OPT_IM, OPT_REG)) +ALT(DEF_ASM_OP2(movb, 0xc6, 0, OPC_MODRM | OPC_BWLX, OPT_IM, OPT_REG | OPT_EA)) + +ALT(DEF_ASM_OP2(movw, 0x8c, 0, OPC_MODRM | OPC_WLX, OPT_SEG, OPT_EA | OPT_REG)) +ALT(DEF_ASM_OP2(movw, 0x8e, 0, OPC_MODRM | OPC_WLX, OPT_EA | OPT_REG, OPT_SEG)) + +ALT(DEF_ASM_OP2(movw, 0x0f20, 0, OPC_MODRM | OPC_WLX, OPT_CR, OPT_REG32)) +ALT(DEF_ASM_OP2(movw, 0x0f21, 0, OPC_MODRM | OPC_WLX, OPT_DB, OPT_REG32)) +ALT(DEF_ASM_OP2(movw, 0x0f24, 0, OPC_MODRM | OPC_WLX, OPT_TR, OPT_REG32)) +ALT(DEF_ASM_OP2(movw, 0x0f22, 0, OPC_MODRM | OPC_WLX, OPT_REG32, OPT_CR)) +ALT(DEF_ASM_OP2(movw, 0x0f23, 0, OPC_MODRM | OPC_WLX, OPT_REG32, OPT_DB)) +ALT(DEF_ASM_OP2(movw, 0x0f26, 0, OPC_MODRM | OPC_WLX, OPT_REG32, OPT_TR)) + +ALT(DEF_ASM_OP2(movsbl, 0x0fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG32)) +ALT(DEF_ASM_OP2(movsbw, 0x660fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG16)) +ALT(DEF_ASM_OP2(movswl, 0x0fbf, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32)) +ALT(DEF_ASM_OP2(movzbw, 0x0fb6, 0, OPC_MODRM | OPC_WLX, OPT_REG8 | OPT_EA, OPT_REGW)) +ALT(DEF_ASM_OP2(movzwl, 0x0fb7, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32)) + +ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WLX, OPT_REGW)) +ALT(DEF_ASM_OP1(pushw, 0xff, 6, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA)) +ALT(DEF_ASM_OP1(pushw, 0x6a, 0, OPC_WLX, OPT_IM8S)) +ALT(DEF_ASM_OP1(pushw, 0x68, 0, OPC_WLX, OPT_IM32)) +ALT(DEF_ASM_OP1(pushw, 0x06, 0, OPC_WLX, OPT_SEG)) + +ALT(DEF_ASM_OP1(popw, 0x58, 0, OPC_REG | OPC_WLX, OPT_REGW)) +ALT(DEF_ASM_OP1(popw, 0x8f, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA)) +ALT(DEF_ASM_OP1(popw, 0x07, 0, OPC_WLX, OPT_SEG)) + +ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WLX, OPT_REGW, OPT_EAX)) +ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WLX, OPT_EAX, OPT_REGW)) +ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) +ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG)) + +ALT(DEF_ASM_OP2(inb, 0xe4, 0, OPC_BWL, OPT_IM8, OPT_EAX)) +ALT(DEF_ASM_OP1(inb, 0xe4, 0, OPC_BWL, OPT_IM8)) +ALT(DEF_ASM_OP2(inb, 0xec, 0, OPC_BWL, OPT_DX, OPT_EAX)) +ALT(DEF_ASM_OP1(inb, 0xec, 0, OPC_BWL, OPT_DX)) + +ALT(DEF_ASM_OP2(outb, 0xe6, 0, OPC_BWL, OPT_EAX, OPT_IM8)) +ALT(DEF_ASM_OP1(outb, 0xe6, 0, OPC_BWL, OPT_IM8)) +ALT(DEF_ASM_OP2(outb, 0xee, 0, OPC_BWL, OPT_EAX, OPT_DX)) +ALT(DEF_ASM_OP1(outb, 0xee, 0, OPC_BWL, OPT_DX)) + +ALT(DEF_ASM_OP2(leaw, 0x8d, 0, OPC_MODRM | OPC_WLX, OPT_EA, OPT_REG)) + +ALT(DEF_ASM_OP2(les, 0xc4, 0, OPC_MODRM, OPT_EA, OPT_REG32)) +ALT(DEF_ASM_OP2(lds, 0xc5, 0, OPC_MODRM, OPT_EA, OPT_REG32)) +ALT(DEF_ASM_OP2(lss, 0x0fb2, 0, OPC_MODRM, OPT_EA, OPT_REG32)) +ALT(DEF_ASM_OP2(lfs, 0x0fb4, 0, OPC_MODRM, OPT_EA, OPT_REG32)) +ALT(DEF_ASM_OP2(lgs, 0x0fb5, 0, OPC_MODRM, OPT_EA, OPT_REG32)) + + /* arith */ +ALT(DEF_ASM_OP2(addb, 0x00, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) /* XXX: use D bit ? */ +ALT(DEF_ASM_OP2(addb, 0x02, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG)) +ALT(DEF_ASM_OP2(addb, 0x04, 0, OPC_ARITH | OPC_BWLX, OPT_IM, OPT_EAX)) +ALT(DEF_ASM_OP2(addw, 0x83, 0, OPC_ARITH | OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_EA | OPT_REGW)) +ALT(DEF_ASM_OP2(addb, 0x80, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_IM, OPT_EA | OPT_REG)) + +ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) +ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG)) +ALT(DEF_ASM_OP2(testb, 0xa8, 0, OPC_BWLX, OPT_IM, OPT_EAX)) +ALT(DEF_ASM_OP2(testb, 0xf6, 0, OPC_MODRM | OPC_BWLX, OPT_IM, OPT_EA | OPT_REG)) + +ALT(DEF_ASM_OP1(incw, 0x40, 0, OPC_REG | OPC_WLX, OPT_REGW)) +ALT(DEF_ASM_OP1(incb, 0xfe, 0, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) +ALT(DEF_ASM_OP1(decw, 0x48, 0, OPC_REG | OPC_WLX, OPT_REGW)) +ALT(DEF_ASM_OP1(decb, 0xfe, 1, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) + +ALT(DEF_ASM_OP1(notb, 0xf6, 2, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) +ALT(DEF_ASM_OP1(negb, 0xf6, 3, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) + +ALT(DEF_ASM_OP1(mulb, 0xf6, 4, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) +ALT(DEF_ASM_OP1(imulb, 0xf6, 5, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) + +ALT(DEF_ASM_OP2(imulw, 0x0faf, 0, OPC_MODRM | OPC_WLX, OPT_REG | OPT_EA, OPT_REG)) +ALT(DEF_ASM_OP3(imulw, 0x6b, 0, OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_REGW | OPT_EA, OPT_REGW)) +ALT(DEF_ASM_OP2(imulw, 0x6b, 0, OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_REGW)) +ALT(DEF_ASM_OP3(imulw, 0x69, 0, OPC_MODRM | OPC_WLX, OPT_IMW, OPT_REGW | OPT_EA, OPT_REGW)) +ALT(DEF_ASM_OP2(imulw, 0x69, 0, OPC_MODRM | OPC_WLX, OPT_IMW, OPT_REGW)) + +ALT(DEF_ASM_OP1(divb, 0xf6, 6, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) +ALT(DEF_ASM_OP2(divb, 0xf6, 6, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA, OPT_EAX)) +ALT(DEF_ASM_OP1(idivb, 0xf6, 7, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA)) +ALT(DEF_ASM_OP2(idivb, 0xf6, 7, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA, OPT_EAX)) + + /* shifts */ +ALT(DEF_ASM_OP2(rolb, 0xc0, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_IM8, OPT_EA | OPT_REG)) +ALT(DEF_ASM_OP2(rolb, 0xd2, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_CL, OPT_EA | OPT_REG)) +ALT(DEF_ASM_OP1(rolb, 0xd0, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_EA | OPT_REG)) + +ALT(DEF_ASM_OP3(shldw, 0x0fa4, 0, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW)) +ALT(DEF_ASM_OP3(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WLX, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW)) +ALT(DEF_ASM_OP2(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_EA | OPT_REGW)) +ALT(DEF_ASM_OP3(shrdw, 0x0fac, 0, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW)) +ALT(DEF_ASM_OP3(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WLX, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW)) +ALT(DEF_ASM_OP2(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_EA | OPT_REGW)) + +ALT(DEF_ASM_OP1(call, 0xff, 2, OPC_MODRM, OPT_INDIR)) +ALT(DEF_ASM_OP1(call, 0xe8, 0, 0, OPT_DISP)) +ALT(DEF_ASM_OP1(jmp, 0xff, 4, OPC_MODRM, OPT_INDIR)) +ALT(DEF_ASM_OP1(jmp, 0xeb, 0, 0, OPT_DISP8)) + +ALT(DEF_ASM_OP2(lcall, 0x9a, 0, 0, OPT_IM16, OPT_IM32)) +ALT(DEF_ASM_OP1(lcall, 0xff, 3, OPC_MODRM, OPT_EA)) +ALT(DEF_ASM_OP2(ljmp, 0xea, 0, 0, OPT_IM16, OPT_IM32)) +ALT(DEF_ASM_OP1(ljmp, 0xff, 5, OPC_MODRM, OPT_EA)) + +ALT(DEF_ASM_OP1(int, 0xcd, 0, 0, OPT_IM8)) +ALT(DEF_ASM_OP1(seto, 0x0f90, 0, OPC_MODRM | OPC_TEST, OPT_REG8 | OPT_EA)) +ALT(DEF_ASM_OP1(setob, 0x0f90, 0, OPC_MODRM | OPC_TEST, OPT_REG8 | OPT_EA)) + DEF_ASM_OP2(enter, 0xc8, 0, 0, OPT_IM16, OPT_IM8) + DEF_ASM_OP0(leave, 0xc9) + DEF_ASM_OP0(ret, 0xc3) + DEF_ASM_OP0(retl,0xc3) +ALT(DEF_ASM_OP1(retl,0xc2, 0, 0, OPT_IM16)) +ALT(DEF_ASM_OP1(ret, 0xc2, 0, 0, OPT_IM16)) + DEF_ASM_OP0(lret, 0xcb) +ALT(DEF_ASM_OP1(lret, 0xca, 0, 0, OPT_IM16)) + +ALT(DEF_ASM_OP1(jo, 0x70, 0, OPC_TEST, OPT_DISP8)) + DEF_ASM_OP1(loopne, 0xe0, 0, 0, OPT_DISP8) + DEF_ASM_OP1(loopnz, 0xe0, 0, 0, OPT_DISP8) + DEF_ASM_OP1(loope, 0xe1, 0, 0, OPT_DISP8) + DEF_ASM_OP1(loopz, 0xe1, 0, 0, OPT_DISP8) + DEF_ASM_OP1(loop, 0xe2, 0, 0, OPT_DISP8) + DEF_ASM_OP1(jecxz, 0xe3, 0, 0, OPT_DISP8) + + /* float */ + /* specific fcomp handling */ +ALT(DEF_ASM_OP0L(fcomp, 0xd8d9, 0, 0)) + +ALT(DEF_ASM_OP1(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST)) +ALT(DEF_ASM_OP2(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0)) +ALT(DEF_ASM_OP2(fadd, 0xdcc0, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) +ALT(DEF_ASM_OP2(fmul, 0xdcc8, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) +ALT(DEF_ASM_OP0L(fadd, 0xdec1, 0, OPC_FARITH)) +ALT(DEF_ASM_OP1(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST)) +ALT(DEF_ASM_OP2(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0)) +ALT(DEF_ASM_OP2(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST)) +ALT(DEF_ASM_OP0L(faddp, 0xdec1, 0, OPC_FARITH)) +ALT(DEF_ASM_OP1(fadds, 0xd8, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) +ALT(DEF_ASM_OP1(fiaddl, 0xda, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) +ALT(DEF_ASM_OP1(faddl, 0xdc, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) +ALT(DEF_ASM_OP1(fiadds, 0xde, 0, OPC_FARITH | OPC_MODRM, OPT_EA)) + + DEF_ASM_OP0(fucompp, 0xdae9) + DEF_ASM_OP0(ftst, 0xd9e4) + DEF_ASM_OP0(fxam, 0xd9e5) + DEF_ASM_OP0(fld1, 0xd9e8) + DEF_ASM_OP0(fldl2t, 0xd9e9) + DEF_ASM_OP0(fldl2e, 0xd9ea) + DEF_ASM_OP0(fldpi, 0xd9eb) + DEF_ASM_OP0(fldlg2, 0xd9ec) + DEF_ASM_OP0(fldln2, 0xd9ed) + DEF_ASM_OP0(fldz, 0xd9ee) + + DEF_ASM_OP0(f2xm1, 0xd9f0) + DEF_ASM_OP0(fyl2x, 0xd9f1) + DEF_ASM_OP0(fptan, 0xd9f2) + DEF_ASM_OP0(fpatan, 0xd9f3) + DEF_ASM_OP0(fxtract, 0xd9f4) + DEF_ASM_OP0(fprem1, 0xd9f5) + DEF_ASM_OP0(fdecstp, 0xd9f6) + DEF_ASM_OP0(fincstp, 0xd9f7) + DEF_ASM_OP0(fprem, 0xd9f8) + DEF_ASM_OP0(fyl2xp1, 0xd9f9) + DEF_ASM_OP0(fsqrt, 0xd9fa) + DEF_ASM_OP0(fsincos, 0xd9fb) + DEF_ASM_OP0(frndint, 0xd9fc) + DEF_ASM_OP0(fscale, 0xd9fd) + DEF_ASM_OP0(fsin, 0xd9fe) + DEF_ASM_OP0(fcos, 0xd9ff) + DEF_ASM_OP0(fchs, 0xd9e0) + DEF_ASM_OP0(fabs, 0xd9e1) + DEF_ASM_OP0(fninit, 0xdbe3) + DEF_ASM_OP0(fnclex, 0xdbe2) + DEF_ASM_OP0(fnop, 0xd9d0) + + /* fp load */ + DEF_ASM_OP1(fld, 0xd9c0, 0, OPC_REG, OPT_ST) + DEF_ASM_OP1(fldl, 0xd9c0, 0, OPC_REG, OPT_ST) + DEF_ASM_OP1(flds, 0xd9, 0, OPC_MODRM, OPT_EA) +ALT(DEF_ASM_OP1(fldl, 0xdd, 0, OPC_MODRM, OPT_EA)) + DEF_ASM_OP1(fildl, 0xdb, 0, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fildq, 0xdf, 5, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fildll, 0xdf, 5, OPC_MODRM,OPT_EA) + DEF_ASM_OP1(fldt, 0xdb, 5, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fbld, 0xdf, 4, OPC_MODRM, OPT_EA) + + /* fp store */ + DEF_ASM_OP1(fst, 0xddd0, 0, OPC_REG, OPT_ST) + DEF_ASM_OP1(fstl, 0xddd0, 0, OPC_REG, OPT_ST) + DEF_ASM_OP1(fsts, 0xd9, 2, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fstps, 0xd9, 3, OPC_MODRM, OPT_EA) +ALT(DEF_ASM_OP1(fstl, 0xdd, 2, OPC_MODRM, OPT_EA)) + DEF_ASM_OP1(fstpl, 0xdd, 3, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fist, 0xdf, 2, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fistp, 0xdf, 3, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fistl, 0xdb, 2, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fistpl, 0xdb, 3, OPC_MODRM, OPT_EA) + + DEF_ASM_OP1(fstp, 0xddd8, 0, OPC_REG, OPT_ST) + DEF_ASM_OP1(fistpq, 0xdf, 7, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fistpll, 0xdf, 7, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fstpt, 0xdb, 7, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(fbstp, 0xdf, 6, OPC_MODRM, OPT_EA) + + /* exchange */ + DEF_ASM_OP0(fxch, 0xd9c9) +ALT(DEF_ASM_OP1(fxch, 0xd9c8, 0, OPC_REG, OPT_ST)) + + /* misc FPU */ + DEF_ASM_OP1(fucom, 0xdde0, 0, OPC_REG, OPT_ST ) + DEF_ASM_OP1(fucomp, 0xdde8, 0, OPC_REG, OPT_ST ) + + DEF_ASM_OP0L(finit, 0xdbe3, 0, OPC_FWAIT) + DEF_ASM_OP1(fldcw, 0xd9, 5, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(fnstcw, 0xd9, 7, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(fstcw, 0xd9, 7, OPC_MODRM | OPC_FWAIT, OPT_EA ) + DEF_ASM_OP0(fnstsw, 0xdfe0) +ALT(DEF_ASM_OP1(fnstsw, 0xdfe0, 0, 0, OPT_EAX )) +ALT(DEF_ASM_OP1(fnstsw, 0xdd, 7, OPC_MODRM, OPT_EA )) + DEF_ASM_OP1(fstsw, 0xdfe0, 0, OPC_FWAIT, OPT_EAX ) +ALT(DEF_ASM_OP0L(fstsw, 0xdfe0, 0, OPC_FWAIT)) +ALT(DEF_ASM_OP1(fstsw, 0xdd, 7, OPC_MODRM | OPC_FWAIT, OPT_EA )) + DEF_ASM_OP0L(fclex, 0xdbe2, 0, OPC_FWAIT) + DEF_ASM_OP1(fnstenv, 0xd9, 6, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(fstenv, 0xd9, 6, OPC_MODRM | OPC_FWAIT, OPT_EA ) + DEF_ASM_OP1(fldenv, 0xd9, 4, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(fnsave, 0xdd, 6, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(fsave, 0xdd, 6, OPC_MODRM | OPC_FWAIT, OPT_EA ) + DEF_ASM_OP1(frstor, 0xdd, 4, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(ffree, 0xddc0, 4, OPC_REG, OPT_ST ) + DEF_ASM_OP1(ffreep, 0xdfc0, 4, OPC_REG, OPT_ST ) + DEF_ASM_OP1(fxsave, 0x0fae, 0, OPC_MODRM, OPT_EA ) + DEF_ASM_OP1(fxrstor, 0x0fae, 1, OPC_MODRM, OPT_EA ) + + /* segments */ + DEF_ASM_OP2(arpl, 0x63, 0, OPC_MODRM, OPT_REG16, OPT_REG16 | OPT_EA) +ALT(DEF_ASM_OP2(larw, 0x0f02, 0, OPC_MODRM | OPC_WLX, OPT_REG | OPT_EA, OPT_REG)) + DEF_ASM_OP1(lgdt, 0x0f01, 2, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(lidt, 0x0f01, 3, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(lldt, 0x0f00, 2, OPC_MODRM, OPT_EA | OPT_REG) + DEF_ASM_OP1(lmsw, 0x0f01, 6, OPC_MODRM, OPT_EA | OPT_REG) +ALT(DEF_ASM_OP2(lslw, 0x0f03, 0, OPC_MODRM | OPC_WLX, OPT_EA | OPT_REG, OPT_REG)) + DEF_ASM_OP1(ltr, 0x0f00, 3, OPC_MODRM, OPT_EA | OPT_REG) + DEF_ASM_OP1(sgdt, 0x0f01, 0, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(sidt, 0x0f01, 1, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(sldt, 0x0f00, 0, OPC_MODRM, OPT_REG | OPT_EA) + DEF_ASM_OP1(smsw, 0x0f01, 4, OPC_MODRM, OPT_REG | OPT_EA) + DEF_ASM_OP1(str, 0x0f00, 1, OPC_MODRM, OPT_REG16| OPT_EA) + DEF_ASM_OP1(verr, 0x0f00, 4, OPC_MODRM, OPT_REG | OPT_EA) + DEF_ASM_OP1(verw, 0x0f00, 5, OPC_MODRM, OPT_REG | OPT_EA) + + /* 486 */ + DEF_ASM_OP1(bswap, 0x0fc8, 0, OPC_REG, OPT_REG32 ) +ALT(DEF_ASM_OP2(xaddb, 0x0fc0, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_REG | OPT_EA )) +ALT(DEF_ASM_OP2(cmpxchgb, 0x0fb0, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_REG | OPT_EA )) + DEF_ASM_OP1(invlpg, 0x0f01, 7, OPC_MODRM, OPT_EA ) + + DEF_ASM_OP2(boundl, 0x62, 0, OPC_MODRM, OPT_REG32, OPT_EA) + DEF_ASM_OP2(boundw, 0x6662, 0, OPC_MODRM, OPT_REG16, OPT_EA) + + /* pentium */ + DEF_ASM_OP1(cmpxchg8b, 0x0fc7, 1, OPC_MODRM, OPT_EA ) + + /* pentium pro */ +ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW)) + DEF_ASM_OP2(fcmovb, 0xdac0, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmove, 0xdac8, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmovbe, 0xdad0, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmovu, 0xdad8, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmovnb, 0xdbc0, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmovne, 0xdbc8, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmovnbe, 0xdbd0, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcmovnu, 0xdbd8, 0, OPC_REG, OPT_ST, OPT_ST0 ) + + DEF_ASM_OP2(fucomi, 0xdbe8, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcomi, 0xdbf0, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fucomip, 0xdfe8, 0, OPC_REG, OPT_ST, OPT_ST0 ) + DEF_ASM_OP2(fcomip, 0xdff0, 0, OPC_REG, OPT_ST, OPT_ST0 ) + + /* mmx */ + DEF_ASM_OP0(emms, 0x0f77) /* must be last OP0 */ + DEF_ASM_OP2(movd, 0x0f6e, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_MMXSSE ) + DEF_ASM_OP2(movq, 0x0f6f, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX ) +ALT(DEF_ASM_OP2(movd, 0x0f7e, 0, OPC_MODRM, OPT_MMXSSE, OPT_EA | OPT_REG32 )) +ALT(DEF_ASM_OP2(movq, 0x0f7f, 0, OPC_MODRM, OPT_MMX, OPT_EA | OPT_MMX )) +ALT(DEF_ASM_OP2(movq, 0x660fd6, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_SSE )) +ALT(DEF_ASM_OP2(movq, 0xf30f7e, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )) + + DEF_ASM_OP2(packssdw, 0x0f6b, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(packsswb, 0x0f63, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(packuswb, 0x0f67, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddb, 0x0ffc, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddw, 0x0ffd, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddd, 0x0ffe, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddsb, 0x0fec, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddsw, 0x0fed, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddusb, 0x0fdc, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(paddusw, 0x0fdd, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pand, 0x0fdb, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pandn, 0x0fdf, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pcmpeqb, 0x0f74, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pcmpeqw, 0x0f75, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pcmpeqd, 0x0f76, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pcmpgtb, 0x0f64, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pcmpgtw, 0x0f65, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pcmpgtd, 0x0f66, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pmaddwd, 0x0ff5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pmulhw, 0x0fe5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pmullw, 0x0fd5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(por, 0x0feb, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psllw, 0x0ff1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psllw, 0x0f71, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(pslld, 0x0ff2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(pslld, 0x0f72, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psllq, 0x0ff3, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psllq, 0x0f73, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psraw, 0x0fe1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psraw, 0x0f71, 4, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psrad, 0x0fe2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psrad, 0x0f72, 4, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psrlw, 0x0fd1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psrlw, 0x0f71, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psrld, 0x0fd2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psrld, 0x0f72, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psrlq, 0x0fd3, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) +ALT(DEF_ASM_OP2(psrlq, 0x0f73, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE )) + DEF_ASM_OP2(psubb, 0x0ff8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psubw, 0x0ff9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psubd, 0x0ffa, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psubsb, 0x0fe8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psubsw, 0x0fe9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psubusb, 0x0fd8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(psubusw, 0x0fd9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(punpckhbw, 0x0f68, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(punpckhwd, 0x0f69, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(punpckhdq, 0x0f6a, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(punpcklbw, 0x0f60, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(punpcklwd, 0x0f61, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(punpckldq, 0x0f62, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pxor, 0x0fef, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + + /* sse */ + DEF_ASM_OP1(ldmxcsr, 0x0fae, 2, OPC_MODRM, OPT_EA) + DEF_ASM_OP1(stmxcsr, 0x0fae, 3, OPC_MODRM, OPT_EA) + DEF_ASM_OP2(movups, 0x0f10, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE ) +ALT(DEF_ASM_OP2(movups, 0x0f11, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 )) + DEF_ASM_OP2(movaps, 0x0f28, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE ) +ALT(DEF_ASM_OP2(movaps, 0x0f29, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 )) + DEF_ASM_OP2(movhps, 0x0f16, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE ) +ALT(DEF_ASM_OP2(movhps, 0x0f17, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 )) + DEF_ASM_OP2(addps, 0x0f58, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(cvtpi2ps, 0x0f2a, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_SSE ) + DEF_ASM_OP2(cvtps2pi, 0x0f2d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX ) + DEF_ASM_OP2(cvttps2pi, 0x0f2c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX ) + DEF_ASM_OP2(divps, 0x0f5e, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(maxps, 0x0f5f, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(minps, 0x0f5d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(mulps, 0x0f59, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(pavgb, 0x0fe0, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(pavgw, 0x0fe3, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(pmaxsw, 0x0fee, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pmaxub, 0x0fde, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pminsw, 0x0fea, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(pminub, 0x0fda, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE ) + DEF_ASM_OP2(rcpss, 0x0f53, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(rsqrtps, 0x0f52, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(sqrtps, 0x0f51, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + DEF_ASM_OP2(subps, 0x0f5c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ) + +#undef ALT +#undef DEF_ASM_OP0 +#undef DEF_ASM_OP0L +#undef DEF_ASM_OP1 +#undef DEF_ASM_OP2 +#undef DEF_ASM_OP3 diff --git a/programs/src/tcc/i386-tok.h b/programs/src/tcc/i386-tok.h new file mode 100644 index 0000000..2907105 --- /dev/null +++ b/programs/src/tcc/i386-tok.h @@ -0,0 +1,332 @@ +/* ------------------------------------------------------------------ */ +/* WARNING: relative order of tokens is important. */ + +#define DEF_BWL(x) \ + DEF(TOK_ASM_ ## x ## b, #x "b") \ + DEF(TOK_ASM_ ## x ## w, #x "w") \ + DEF(TOK_ASM_ ## x ## l, #x "l") \ + DEF(TOK_ASM_ ## x, #x) +#define DEF_WL(x) \ + DEF(TOK_ASM_ ## x ## w, #x "w") \ + DEF(TOK_ASM_ ## x ## l, #x "l") \ + DEF(TOK_ASM_ ## x, #x) +#ifdef TCC_TARGET_X86_64 +# define DEF_BWLQ(x) \ + DEF(TOK_ASM_ ## x ## b, #x "b") \ + DEF(TOK_ASM_ ## x ## w, #x "w") \ + DEF(TOK_ASM_ ## x ## l, #x "l") \ + DEF(TOK_ASM_ ## x ## q, #x "q") \ + DEF(TOK_ASM_ ## x, #x) +# define DEF_WLQ(x) \ + DEF(TOK_ASM_ ## x ## w, #x "w") \ + DEF(TOK_ASM_ ## x ## l, #x "l") \ + DEF(TOK_ASM_ ## x ## q, #x "q") \ + DEF(TOK_ASM_ ## x, #x) +# define DEF_BWLX DEF_BWLQ +# define DEF_WLX DEF_WLQ +/* number of sizes + 1 */ +# define NBWLX 5 +#else +# define DEF_BWLX DEF_BWL +# define DEF_WLX DEF_WL +/* number of sizes + 1 */ +# define NBWLX 4 +#endif + +#define DEF_FP1(x) \ + DEF(TOK_ASM_ ## f ## x ## s, "f" #x "s") \ + DEF(TOK_ASM_ ## fi ## x ## l, "fi" #x "l") \ + DEF(TOK_ASM_ ## f ## x ## l, "f" #x "l") \ + DEF(TOK_ASM_ ## fi ## x ## s, "fi" #x "s") + +#define DEF_FP(x) \ + DEF(TOK_ASM_ ## f ## x, "f" #x ) \ + DEF(TOK_ASM_ ## f ## x ## p, "f" #x "p") \ + DEF_FP1(x) + +#define DEF_ASMTEST(x,suffix) \ + DEF_ASM(x ## o ## suffix) \ + DEF_ASM(x ## no ## suffix) \ + DEF_ASM(x ## b ## suffix) \ + DEF_ASM(x ## c ## suffix) \ + DEF_ASM(x ## nae ## suffix) \ + DEF_ASM(x ## nb ## suffix) \ + DEF_ASM(x ## nc ## suffix) \ + DEF_ASM(x ## ae ## suffix) \ + DEF_ASM(x ## e ## suffix) \ + DEF_ASM(x ## z ## suffix) \ + DEF_ASM(x ## ne ## suffix) \ + DEF_ASM(x ## nz ## suffix) \ + DEF_ASM(x ## be ## suffix) \ + DEF_ASM(x ## na ## suffix) \ + DEF_ASM(x ## nbe ## suffix) \ + DEF_ASM(x ## a ## suffix) \ + DEF_ASM(x ## s ## suffix) \ + DEF_ASM(x ## ns ## suffix) \ + DEF_ASM(x ## p ## suffix) \ + DEF_ASM(x ## pe ## suffix) \ + DEF_ASM(x ## np ## suffix) \ + DEF_ASM(x ## po ## suffix) \ + DEF_ASM(x ## l ## suffix) \ + DEF_ASM(x ## nge ## suffix) \ + DEF_ASM(x ## nl ## suffix) \ + DEF_ASM(x ## ge ## suffix) \ + DEF_ASM(x ## le ## suffix) \ + DEF_ASM(x ## ng ## suffix) \ + DEF_ASM(x ## nle ## suffix) \ + DEF_ASM(x ## g ## suffix) + +/* ------------------------------------------------------------------ */ +/* register */ + DEF_ASM(al) + DEF_ASM(cl) + DEF_ASM(dl) + DEF_ASM(bl) + DEF_ASM(ah) + DEF_ASM(ch) + DEF_ASM(dh) + DEF_ASM(bh) + DEF_ASM(ax) + DEF_ASM(cx) + DEF_ASM(dx) + DEF_ASM(bx) + DEF_ASM(sp) + DEF_ASM(bp) + DEF_ASM(si) + DEF_ASM(di) + DEF_ASM(eax) + DEF_ASM(ecx) + DEF_ASM(edx) + DEF_ASM(ebx) + DEF_ASM(esp) + DEF_ASM(ebp) + DEF_ASM(esi) + DEF_ASM(edi) +#ifdef TCC_TARGET_X86_64 + DEF_ASM(rax) + DEF_ASM(rcx) + DEF_ASM(rdx) + DEF_ASM(rbx) + DEF_ASM(rsp) + DEF_ASM(rbp) + DEF_ASM(rsi) + DEF_ASM(rdi) +#endif + DEF_ASM(mm0) + DEF_ASM(mm1) + DEF_ASM(mm2) + DEF_ASM(mm3) + DEF_ASM(mm4) + DEF_ASM(mm5) + DEF_ASM(mm6) + DEF_ASM(mm7) + DEF_ASM(xmm0) + DEF_ASM(xmm1) + DEF_ASM(xmm2) + DEF_ASM(xmm3) + DEF_ASM(xmm4) + DEF_ASM(xmm5) + DEF_ASM(xmm6) + DEF_ASM(xmm7) + DEF_ASM(cr0) + DEF_ASM(cr1) + DEF_ASM(cr2) + DEF_ASM(cr3) + DEF_ASM(cr4) + DEF_ASM(cr5) + DEF_ASM(cr6) + DEF_ASM(cr7) + DEF_ASM(tr0) + DEF_ASM(tr1) + DEF_ASM(tr2) + DEF_ASM(tr3) + DEF_ASM(tr4) + DEF_ASM(tr5) + DEF_ASM(tr6) + DEF_ASM(tr7) + DEF_ASM(db0) + DEF_ASM(db1) + DEF_ASM(db2) + DEF_ASM(db3) + DEF_ASM(db4) + DEF_ASM(db5) + DEF_ASM(db6) + DEF_ASM(db7) + DEF_ASM(dr0) + DEF_ASM(dr1) + DEF_ASM(dr2) + DEF_ASM(dr3) + DEF_ASM(dr4) + DEF_ASM(dr5) + DEF_ASM(dr6) + DEF_ASM(dr7) + DEF_ASM(es) + DEF_ASM(cs) + DEF_ASM(ss) + DEF_ASM(ds) + DEF_ASM(fs) + DEF_ASM(gs) + DEF_ASM(st) + DEF_ASM(rip) + +#ifdef TCC_TARGET_X86_64 + /* The four low parts of sp/bp/si/di that exist only on + x86-64 (encoding aliased to ah,ch,dh,dh when not using REX). */ + DEF_ASM(spl) + DEF_ASM(bpl) + DEF_ASM(sil) + DEF_ASM(dil) +#endif + /* generic two operands */ + DEF_BWLX(mov) + + DEF_BWLX(add) + DEF_BWLX(or) + DEF_BWLX(adc) + DEF_BWLX(sbb) + DEF_BWLX(and) + DEF_BWLX(sub) + DEF_BWLX(xor) + DEF_BWLX(cmp) + + /* unary ops */ + DEF_BWLX(inc) + DEF_BWLX(dec) + DEF_BWLX(not) + DEF_BWLX(neg) + DEF_BWLX(mul) + DEF_BWLX(imul) + DEF_BWLX(div) + DEF_BWLX(idiv) + + DEF_BWLX(xchg) + DEF_BWLX(test) + + /* shifts */ + DEF_BWLX(rol) + DEF_BWLX(ror) + DEF_BWLX(rcl) + DEF_BWLX(rcr) + DEF_BWLX(shl) + DEF_BWLX(shr) + DEF_BWLX(sar) + + DEF_WLX(shld) + DEF_WLX(shrd) + + DEF_ASM(pushw) + DEF_ASM(pushl) +#ifdef TCC_TARGET_X86_64 + DEF_ASM(pushq) +#endif + DEF_ASM(push) + + DEF_ASM(popw) + DEF_ASM(popl) +#ifdef TCC_TARGET_X86_64 + DEF_ASM(popq) +#endif + DEF_ASM(pop) + + DEF_BWL(in) + DEF_BWL(out) + + DEF_WLX(movzb) + DEF_ASM(movzwl) + DEF_ASM(movsbw) + DEF_ASM(movsbl) + DEF_ASM(movswl) +#ifdef TCC_TARGET_X86_64 + DEF_ASM(movsbq) + DEF_ASM(movswq) + DEF_ASM(movzwq) + DEF_ASM(movslq) +#endif + + DEF_WLX(lea) + + DEF_ASM(les) + DEF_ASM(lds) + DEF_ASM(lss) + DEF_ASM(lfs) + DEF_ASM(lgs) + + DEF_ASM(call) + DEF_ASM(jmp) + DEF_ASM(lcall) + DEF_ASM(ljmp) + + DEF_ASMTEST(j,) + + DEF_ASMTEST(set,) + DEF_ASMTEST(set,b) + DEF_ASMTEST(cmov,) + + DEF_WLX(bsf) + DEF_WLX(bsr) + DEF_WLX(bt) + DEF_WLX(bts) + DEF_WLX(btr) + DEF_WLX(btc) + DEF_WLX(popcnt) + DEF_WLX(tzcnt) + DEF_WLX(lzcnt) + + DEF_WLX(lar) + DEF_WLX(lsl) + + /* generic FP ops */ + DEF_FP(add) + DEF_FP(mul) + + DEF_ASM(fcom) + DEF_ASM(fcom_1) /* non existent op, just to have a regular table */ + DEF_FP1(com) + + DEF_FP(comp) + DEF_FP(sub) + DEF_FP(subr) + DEF_FP(div) + DEF_FP(divr) + + DEF_BWLX(xadd) + DEF_BWLX(cmpxchg) + + /* string ops */ + DEF_BWLX(cmps) + DEF_BWLX(scmp) + DEF_BWL(ins) + DEF_BWL(outs) + DEF_BWLX(lods) + DEF_BWLX(slod) + DEF_BWLX(movs) + DEF_BWLX(smov) + DEF_BWLX(scas) + DEF_BWLX(ssca) + DEF_BWLX(stos) + DEF_BWLX(ssto) + + /* generic asm ops */ +#define ALT(x) +#define DEF_ASM_OP0(name, opcode) DEF_ASM(name) +#define DEF_ASM_OP0L(name, opcode, group, instr_type) +#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) +#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) +#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) +#ifdef TCC_TARGET_X86_64 +# include "x86_64-asm.h" +#else +# include "i386-asm.h" +#endif + +#define ALT(x) +#define DEF_ASM_OP0(name, opcode) +#define DEF_ASM_OP0L(name, opcode, group, instr_type) DEF_ASM(name) +#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) DEF_ASM(name) +#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) DEF_ASM(name) +#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) DEF_ASM(name) +#ifdef TCC_TARGET_X86_64 +# include "x86_64-asm.h" +#else +# include "i386-asm.h" +#endif diff --git a/programs/src/tcc/libtcc.c b/programs/src/tcc/libtcc.c new file mode 100644 index 0000000..b73c122 --- /dev/null +++ b/programs/src/tcc/libtcc.c @@ -0,0 +1,2272 @@ +/* + * TCC - Tiny C Compiler + * + * Copyright (c) 2001-2004 Fabrice Bellard + * + * This 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 of the License, or (at your option) any later version. + * + * This 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 this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ONE_SOURCE +# define ONE_SOURCE 1 +#endif + +#if ONE_SOURCE +#include "tccpp.c" +#include "tccgen.c" +#include "tccdbg.c" +#include "tccasm.c" +#include "tccelf.c" +#include "tccrun.c" +#ifdef TCC_TARGET_I386 +#include "i386-gen.c" +#include "i386-link.c" +#include "i386-asm.c" +#elif defined(TCC_TARGET_ARM) +#include "arm-gen.c" +#include "arm-link.c" +#include "arm-asm.c" +#elif defined(TCC_TARGET_ARM64) +#include "arm64-gen.c" +#include "arm64-link.c" +#include "arm64-asm.c" +#elif defined(TCC_TARGET_C67) +#include "c67-gen.c" +#include "c67-link.c" +#include "tcccoff.c" +#elif defined(TCC_TARGET_X86_64) +#include "x86_64-gen.c" +#include "x86_64-link.c" +#include "i386-asm.c" +#elif defined(TCC_TARGET_RISCV64) +#include "riscv64-gen.c" +#include "riscv64-link.c" +#include "riscv64-asm.c" +#else +#error unknown target +#endif +#ifdef TCC_TARGET_PE +#include "tccpe.c" +#endif +#ifdef TCC_TARGET_MACHO +#include "tccmacho.c" +#endif +#endif /* ONE_SOURCE */ + +#include "tcc.h" + +/********************************************************/ +/* global variables */ + +/* XXX: get rid of this ASAP (or maybe not) */ +ST_DATA struct TCCState *tcc_state; +TCC_SEM(static tcc_compile_sem); +/* an array of pointers to memory to be free'd after errors */ +ST_DATA void** stk_data; +ST_DATA int nb_stk_data; +/* option -d (for general development purposes) */ +ST_DATA int g_debug; + +/********************************************************/ +#ifdef _WIN32 +ST_FUNC char *normalize_slashes(char *path) +{ + char *p; + for (p = path; *p; ++p) + if (*p == '\\') + *p = '/'; + return path; +} + +#if defined LIBTCC_AS_DLL && !defined CONFIG_TCCDIR +static HMODULE tcc_module; +BOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved) +{ + if (DLL_PROCESS_ATTACH == dwReason) + tcc_module = hDll; + return TRUE; +} +#else +#define tcc_module NULL /* NULL means executable itself */ +#endif + +#ifndef CONFIG_TCCDIR +/* on win32, we suppose the lib and includes are at the location of 'tcc.exe' */ +static inline char *config_tccdir_w32(char *path) +{ + char *p; + GetModuleFileNameA(tcc_module, path, MAX_PATH); + p = tcc_basename(normalize_slashes(strlwr(path))); + if (p > path) + --p; + *p = 0; + return path; +} +#define CONFIG_TCCDIR config_tccdir_w32(alloca(MAX_PATH)) +#endif + +#ifdef TCC_IS_NATIVE +static void tcc_add_systemdir(TCCState *s) +{ + char buf[1000]; + GetSystemDirectoryA(buf, sizeof buf); + tcc_add_library_path(s, normalize_slashes(buf)); +} +#endif +#endif + +/********************************************************/ + +PUB_FUNC void tcc_enter_state(TCCState *s1) +{ + if (s1->error_set_jmp_enabled) + return; + WAIT_SEM(&tcc_compile_sem); + tcc_state = s1; +} + +PUB_FUNC void tcc_exit_state(TCCState *s1) +{ + if (s1->error_set_jmp_enabled) + return; + tcc_state = NULL; + POST_SEM(&tcc_compile_sem); +} + +/********************************************************/ +/* copy a string and truncate it. */ +ST_FUNC char *pstrcpy(char *buf, size_t buf_size, const char *s) +{ + char *q, *q_end; + int c; + + if (buf_size > 0) { + q = buf; + q_end = buf + buf_size - 1; + while (q < q_end) { + c = *s++; + if (c == '\0') + break; + *q++ = c; + } + *q = '\0'; + } + return buf; +} + +/* strcat and truncate. */ +ST_FUNC char *pstrcat(char *buf, size_t buf_size, const char *s) +{ + size_t len; + len = strlen(buf); + if (len < buf_size) + pstrcpy(buf + len, buf_size - len, s); + return buf; +} + +ST_FUNC char *pstrncpy(char *out, size_t buf_size, const char *s, size_t num) +{ + if (num >= buf_size) + num = buf_size - 1; + memcpy(out, s, num); + out[num] = '\0'; + return out; +} + +/* extract the basename of a file */ +PUB_FUNC char *tcc_basename(const char *name) +{ + char *p = strchr(name, 0); + while (p > name && !IS_DIRSEP(p[-1])) + --p; + return p; +} + +/* extract extension part of a file + * + * (if no extension, return pointer to end-of-string) + */ +PUB_FUNC char *tcc_fileextension (const char *name) +{ + char *b = tcc_basename(name); + char *e = strrchr(b, '.'); + return e ? e : strchr(b, 0); +} + +ST_FUNC char *tcc_load_text(int fd) +{ + int len = lseek(fd, 0, SEEK_END); + char *buf = load_data(fd, 0, len + 1); + buf[len] = 0; + return buf; +} + +/* replace *pp by copy of 'str' or NULL */ +static void tcc_set_str(char **pp, const char *str) +{ + tcc_free(*pp); + *pp = str ? tcc_strdup(str) : NULL; +} + +/* set/append 'str' to *pp (separated by 'sep' unless 0) */ +static void tcc_concat_str(char **pp, const char *str, int sep) +{ + int l = *pp ? strlen(*pp) + !!sep : 0; + *pp = tcc_realloc(*pp, l + strlen(str) + 1); + if (l && sep) ((*pp)[l - 1] = sep); + strcpy(*pp + l, str); +} + +/********************************************************/ +/* memory management */ + +/* we'll need the actual versions for a minute */ +#undef free +#undef realloc + +static void *default_reallocator(void *ptr, unsigned long size) +{ + void *ptr1; + if (size == 0) { + free(ptr); + ptr1 = NULL; + } + else { + ptr1 = realloc(ptr, size); + if (!ptr1) { + fprintf(stderr, "memory full\n"); + exit (1); + } + } + return ptr1; +} + +ST_FUNC void libc_free(void *ptr) +{ + free(ptr); +} + +/* defined to be not used */ +#define free(p) use_tcc_free(p) +#define realloc(p, s) use_tcc_realloc(p, s) + +/* global so that every tcc_alloc()/tcc_free() call doesn't need to be changed */ +static void *(*reallocator)(void*, unsigned long) = default_reallocator; + +LIBTCCAPI void tcc_set_realloc(TCCReallocFunc *realloc) +{ + reallocator = realloc ? realloc : default_reallocator; +} + +/* in case MEM_DEBUG is #defined */ +#undef tcc_free +#undef tcc_malloc +#undef tcc_realloc +#undef tcc_mallocz +#undef tcc_strdup + +PUB_FUNC void tcc_free(void *ptr) +{ + reallocator(ptr, 0); +} + +PUB_FUNC void *tcc_malloc(unsigned long size) +{ + return reallocator(0, size); +} + +PUB_FUNC void *tcc_realloc(void *ptr, unsigned long size) +{ + return reallocator(ptr, size); +} + +PUB_FUNC void *tcc_mallocz(unsigned long size) +{ + void *ptr; + ptr = tcc_malloc(size); + if (size) + memset(ptr, 0, size); + return ptr; +} + +PUB_FUNC char *tcc_strdup(const char *str) +{ + char *ptr; + ptr = tcc_malloc(strlen(str) + 1); + strcpy(ptr, str); + return ptr; +} + +#ifdef MEM_DEBUG + +#define MEM_DEBUG_MAGIC1 0xFEEDDEB1 +#define MEM_DEBUG_MAGIC2 0xFEEDDEB2 +#define MEM_DEBUG_MAGIC3 0xFEEDDEB3 +#define MEM_DEBUG_FILE_LEN 40 +#define MEM_DEBUG_CHECK3(header) \ + (((unsigned char *) header->magic3) + header->size) +#define MEM_USER_PTR(header) \ + ((char *)header + offsetof(mem_debug_header_t, magic3)) +#define MEM_HEADER_PTR(ptr) \ + (mem_debug_header_t *)((char*)ptr - offsetof(mem_debug_header_t, magic3)) + +struct mem_debug_header { + unsigned magic1; + unsigned size; + struct mem_debug_header *prev; + struct mem_debug_header *next; + int line_num; + char file_name[MEM_DEBUG_FILE_LEN]; + unsigned magic2; + ALIGNED(16) unsigned char magic3[4]; +}; + +typedef struct mem_debug_header mem_debug_header_t; + +TCC_SEM(static mem_sem); +static mem_debug_header_t *mem_debug_chain; +static unsigned mem_cur_size; +static unsigned mem_max_size; +static int nb_states; + +static mem_debug_header_t *malloc_check(void *ptr, const char *msg) +{ + mem_debug_header_t * header = MEM_HEADER_PTR(ptr); + if (header->magic1 != MEM_DEBUG_MAGIC1 || + header->magic2 != MEM_DEBUG_MAGIC2 || + read32le(MEM_DEBUG_CHECK3(header)) != MEM_DEBUG_MAGIC3 || + header->size == (unsigned)-1) { + fprintf(stderr, "%s check failed\n", msg); + if (header->magic1 == MEM_DEBUG_MAGIC1) + fprintf(stderr, "%s:%u: block allocated here.\n", + header->file_name, header->line_num); + exit(1); + } + return header; +} + +PUB_FUNC void *tcc_malloc_debug(unsigned long size, const char *file, int line) +{ + int ofs; + mem_debug_header_t *header; + if (!size) + return NULL; + header = tcc_malloc(sizeof(mem_debug_header_t) + size); + header->magic1 = MEM_DEBUG_MAGIC1; + header->magic2 = MEM_DEBUG_MAGIC2; + header->size = size; + write32le(MEM_DEBUG_CHECK3(header), MEM_DEBUG_MAGIC3); + header->line_num = line; + ofs = strlen(file) + 1 - MEM_DEBUG_FILE_LEN; + strcpy(header->file_name, file + (ofs > 0 ? ofs : 0)); + WAIT_SEM(&mem_sem); + header->next = mem_debug_chain; + header->prev = NULL; + if (header->next) + header->next->prev = header; + mem_debug_chain = header; + mem_cur_size += size; + if (mem_cur_size > mem_max_size) + mem_max_size = mem_cur_size; + POST_SEM(&mem_sem); + return MEM_USER_PTR(header); +} + +PUB_FUNC void tcc_free_debug(void *ptr) +{ + mem_debug_header_t *header; + if (!ptr) + return; + header = malloc_check(ptr, "tcc_free"); + WAIT_SEM(&mem_sem); + mem_cur_size -= header->size; + header->size = (unsigned)-1; + if (header->next) + header->next->prev = header->prev; + if (header->prev) + header->prev->next = header->next; + if (header == mem_debug_chain) + mem_debug_chain = header->next; + POST_SEM(&mem_sem); + tcc_free(header); +} + +PUB_FUNC void *tcc_mallocz_debug(unsigned long size, const char *file, int line) +{ + void *ptr; + ptr = tcc_malloc_debug(size,file,line); + if (size) + memset(ptr, 0, size); + return ptr; +} + +PUB_FUNC void *tcc_realloc_debug(void *ptr, unsigned long size, const char *file, int line) +{ + mem_debug_header_t *header; + int mem_debug_chain_update = 0; + + if (!ptr) + return tcc_malloc_debug(size, file, line); + if (!size) { + tcc_free_debug(ptr); + return NULL; + } + header = malloc_check(ptr, "tcc_realloc"); + WAIT_SEM(&mem_sem); + mem_cur_size -= header->size; + mem_debug_chain_update = (header == mem_debug_chain); + header = tcc_realloc(header, sizeof(mem_debug_header_t) + size); + header->size = size; + write32le(MEM_DEBUG_CHECK3(header), MEM_DEBUG_MAGIC3); + if (header->next) + header->next->prev = header; + if (header->prev) + header->prev->next = header; + if (mem_debug_chain_update) + mem_debug_chain = header; + mem_cur_size += size; + if (mem_cur_size > mem_max_size) + mem_max_size = mem_cur_size; + POST_SEM(&mem_sem); + return MEM_USER_PTR(header); +} + +PUB_FUNC char *tcc_strdup_debug(const char *str, const char *file, int line) +{ + char *ptr; + ptr = tcc_malloc_debug(strlen(str) + 1, file, line); + strcpy(ptr, str); + return ptr; +} + +PUB_FUNC void tcc_memcheck(int d) +{ + WAIT_SEM(&mem_sem); + nb_states += d; + if (0 == nb_states && mem_cur_size) { + mem_debug_header_t *header = mem_debug_chain; + fflush(stdout); + fprintf(stderr, "MEM_DEBUG: mem_leak= %d bytes, mem_max_size= %d bytes\n", + mem_cur_size, mem_max_size); + while (header) { + fprintf(stderr, "%s:%u: error: %u bytes leaked\n", + header->file_name, header->line_num, header->size); + header = header->next; + } + fflush(stderr); + mem_cur_size = 0; + mem_max_size = 0; + mem_debug_chain = NULL; +#if MEM_DEBUG-0 == 2 + exit(2); +#endif + } + POST_SEM(&mem_sem); +} + +/* restore the debug versions */ +#define tcc_free(ptr) tcc_free_debug(ptr) +#define tcc_malloc(size) tcc_malloc_debug(size, __FILE__, __LINE__) +#define tcc_mallocz(size) tcc_mallocz_debug(size, __FILE__, __LINE__) +#define tcc_realloc(ptr,size) tcc_realloc_debug(ptr, size, __FILE__, __LINE__) +#define tcc_strdup(str) tcc_strdup_debug(str, __FILE__, __LINE__) + +#endif /* MEM_DEBUG */ + +#ifdef _WIN32 +# define realpath(file, buf) _fullpath(buf, file, 260) +#endif + +/* for #pragma once */ +ST_FUNC int normalized_PATHCMP(const char *f1, const char *f2) +{ + char *p1, *p2; + int ret = 1; + if (!!(p1 = realpath(f1, NULL))) { + if (!!(p2 = realpath(f2, NULL))) { + ret = PATHCMP(p1, p2); + libc_free(p2); /* realpath() requirement */ + } + libc_free(p1); + } + return ret; +} + +/********************************************************/ +/* dynarrays */ + +ST_FUNC void dynarray_add(void *ptab, int *nb_ptr, void *data) +{ + int nb, nb_alloc; + void **pp; + + nb = *nb_ptr; + pp = *(void ***)ptab; + /* every power of two we double array size */ + if ((nb & (nb - 1)) == 0) { + if (!nb) + nb_alloc = 1; + else + nb_alloc = nb * 2; + pp = tcc_realloc(pp, nb_alloc * sizeof(void *)); + *(void***)ptab = pp; + } + pp[nb++] = data; + *nb_ptr = nb; +} + +ST_FUNC void dynarray_reset(void *pp, int *n) +{ + void **p; + for (p = *(void***)pp; *n; ++p, --*n) + if (*p) + tcc_free(*p); + tcc_free(*(void**)pp); + *(void**)pp = NULL; +} + +static void dynarray_split(char ***argv, int *argc, const char *p, int sep) +{ + int qot, c; + CString str; + for(;;) { + while (c = (unsigned char)*p, c <= ' ' && c != '\0') + ++p; + if (c == '\0') + break; + cstr_new(&str); + qot = 0; + do { + ++p; + if (sep) { /* e.g. to split -Wl,-opt,arg */ + if (c == sep) + break; + } else { + /* e.g. for tcc_set_options() or "tcc @listfile" */ + if (c == '\\' && (*p == '"' || *p == '\\')) { + c = *p++; + } else if (c == '"') { + qot ^= 1; + continue; + } else if (c <= ' ' && !qot) { + break; + } + } + cstr_ccat(&str, c); + } while (c = (unsigned char)*p, c != '\0'); + cstr_ccat(&str, '\0'); + //printf("<%s>\n", str.data); + dynarray_add(argv, argc, str.data); + } +} + +static void tcc_split_path(TCCState *s, void *p_ary, int *p_nb_ary, const char *in) +{ + const char *p; + do { + int c; + CString str; + + cstr_new(&str); + for (p = in; c = *p, c != '\0' && c != PATHSEP[0]; ++p) { + if (c == '{' && p[1] && p[2] == '}') { + c = p[1], p += 2; + if (c == 'B') + cstr_cat(&str, s->tcc_lib_path, -1); + if (c == 'R') + cstr_cat(&str, CONFIG_SYSROOT, -1); + if (c == 'f' && file) { + /* substitute current file's dir */ + const char *f = file->true_filename; + const char *b = tcc_basename(f); + if (b > f) + cstr_cat(&str, f, b - f - 1); + else + cstr_cat(&str, ".", 1); + } + } else { + cstr_ccat(&str, c); + } + } + if (str.size) { + cstr_ccat(&str, '\0'); + dynarray_add(p_ary, p_nb_ary, str.data); + } + in = p+1; + } while (*p); +} + +/********************************************************/ +/* warning / error */ + +/* warn_... option bits */ +#define WARN_ON 1 /* warning is on (-Woption) */ +#define WARN_ERR 2 /* warning is an error (-Werror=option) */ +#define WARN_NOE 4 /* warning is not an error (-Wno-error=option) */ + +/* error1() modes */ +enum { ERROR_WARN, ERROR_NOABORT, ERROR_ERROR }; + +static void error1(int mode, const char *fmt, va_list ap) +{ + BufferedFile **pf, *f; + TCCState *s1 = tcc_state; + CString cs; + int line = 0; + + tcc_exit_state(s1); + + if (mode == ERROR_WARN) { + if (s1->warn_error) + mode = ERROR_ERROR; + if (s1->warn_num) { + /* handle tcc_warning_c(warn_option)(fmt, ...) */ + int wopt = *(&s1->warn_none + s1->warn_num); + s1->warn_num = 0; + if (0 == (wopt & WARN_ON)) + return; + if (wopt & WARN_ERR) + mode = ERROR_ERROR; + if (wopt & WARN_NOE) + mode = ERROR_WARN; + } + if (s1->warn_none) + return; + } + + cstr_new(&cs); + if (fmt[0] == '%' && fmt[1] == 'i' && fmt[2] == ':') + line = va_arg(ap, int), fmt += 3; + f = NULL; + if (s1->error_set_jmp_enabled) { /* we're called while parsing a file */ + /* use upper file if inline ":asm:" or token ":paste:" */ + for (f = file; f && f->filename[0] == ':'; f = f->prev) + ; + } + if (f) { + for(pf = s1->include_stack; pf < s1->include_stack_ptr; pf++) + cstr_printf(&cs, "In file included from %s:%d:\n", + (*pf)->filename, (*pf)->line_num - 1); + if (0 == line) + line = f->line_num - ((tok_flags & TOK_FLAG_BOL) && !macro_ptr); + cstr_printf(&cs, "%s:%d: ", f->filename, line); + } else if (s1->current_filename) { + cstr_printf(&cs, "%s: ", s1->current_filename); + } else { + cstr_printf(&cs, "tcc: "); + } + cstr_printf(&cs, mode == ERROR_WARN ? "warning: " : "error: "); + if (pp_expr > 1) + pp_error(&cs); /* special handler for preprocessor expression errors */ + else + cstr_vprintf(&cs, fmt, ap); + if (!s1->error_func) { + /* default case: stderr */ + if (s1 && s1->output_type == TCC_OUTPUT_PREPROCESS && s1->ppfp == stdout) + printf("\n"); /* print a newline during tcc -E */ + fflush(stdout); /* flush -v output */ + fprintf(stderr, "%s\n", (char*)cs.data); + fflush(stderr); /* print error/warning now (win32) */ + } else { + s1->error_func(s1->error_opaque, (char*)cs.data); + } + cstr_free(&cs); + if (mode != ERROR_WARN) + s1->nb_errors++; + if (mode == ERROR_ERROR && s1->error_set_jmp_enabled) { + while (nb_stk_data) + tcc_free(*(void**)stk_data[--nb_stk_data]); + longjmp(s1->error_jmp_buf, 1); + } +} + +LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, TCCErrorFunc *error_func) +{ + s->error_opaque = error_opaque; + s->error_func = error_func; +} + +/* error without aborting current compilation */ +PUB_FUNC int _tcc_error_noabort(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + error1(ERROR_NOABORT, fmt, ap); + va_end(ap); + return -1; +} + +#undef _tcc_error +PUB_FUNC void _tcc_error(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + error1(ERROR_ERROR, fmt, ap); + exit(1); +} +#define _tcc_error use_tcc_error_noabort + +PUB_FUNC void _tcc_warning(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + error1(ERROR_WARN, fmt, ap); + va_end(ap); +} + + +/********************************************************/ +/* I/O layer */ + +ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen) +{ + BufferedFile *bf; + int buflen = initlen ? initlen : IO_BUF_SIZE; + + bf = tcc_mallocz(sizeof(BufferedFile) + buflen); + bf->buf_ptr = bf->buffer; + bf->buf_end = bf->buffer + initlen; + bf->buf_end[0] = CH_EOB; /* put eob symbol */ + pstrcpy(bf->filename, sizeof(bf->filename), filename); +#ifdef _WIN32 + normalize_slashes(bf->filename); +#endif + bf->true_filename = bf->filename; + bf->line_num = 1; + bf->ifdef_stack_ptr = s1->ifdef_stack_ptr; + bf->fd = -1; + bf->prev = file; + bf->prev_tok_flags = tok_flags; + file = bf; + tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; +} + +ST_FUNC void tcc_close(void) +{ + TCCState *s1 = tcc_state; + BufferedFile *bf = file; + if (bf->fd > 0) { + close(bf->fd); + total_lines += bf->line_num - 1; + } + if (bf->true_filename != bf->filename) + tcc_free(bf->true_filename); + file = bf->prev; + tok_flags = bf->prev_tok_flags; + tcc_free(bf); +} + +static int _tcc_open(TCCState *s1, const char *filename) +{ + int fd; + if (strcmp(filename, "-") == 0) + fd = 0, filename = ""; + else + fd = open(filename, O_RDONLY | O_BINARY); + if ((s1->verbose == 2 && fd >= 0) || s1->verbose == 3) + printf("%s %*s%s\n", fd < 0 ? "nf":"->", + (int)(s1->include_stack_ptr - s1->include_stack), "", filename); + return fd; +} + +ST_FUNC int tcc_open(TCCState *s1, const char *filename) +{ + int fd = _tcc_open(s1, filename); + if (fd < 0) + return -1; + tcc_open_bf(s1, filename, 0); + file->fd = fd; + return 0; +} + +/* compile the file opened in 'file'. Return non zero if errors. */ +static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd, const char *filename) +{ + /* Here we enter the code section where we use the global variables for + parsing and code generation (tccpp.c, tccgen.c, -gen.c). + Other threads need to wait until we're done. + + Alternatively we could use thread local storage for those global + variables, which may or may not have advantages */ + + tcc_enter_state(s1); + s1->error_set_jmp_enabled = 1; + + if (setjmp(s1->error_jmp_buf) == 0) { + + if (fd == -1) { + int len = strlen(str); + tcc_open_bf(s1, filename ? filename : "", len); + memcpy(file->buffer, str, len); + if (s1->do_debug && filename) { + FILE *fp = fopen(filename, "w"); + + if (fp) { + fputs(str, fp); + fclose(fp); + } + } + } else { + tcc_open_bf(s1, str, 0); + file->fd = fd; + } + + preprocess_start(s1, filetype); + tccgen_init(s1); + + if (s1->output_type == TCC_OUTPUT_PREPROCESS) { + tcc_preprocess(s1); + } else { + tccelf_begin_file(s1); + if (filetype & (AFF_TYPE_ASM | AFF_TYPE_ASMPP)) { + tcc_assemble(s1, !!(filetype & AFF_TYPE_ASMPP)); + } else { + tccgen_compile(s1); + } + tccelf_end_file(s1); + } + } + tccgen_finish(s1); + preprocess_end(s1); + s1->error_set_jmp_enabled = 0; + tcc_exit_state(s1); + return s1->nb_errors != 0 ? -1 : 0; +} + +LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str) +{ + return tcc_compile(s, s->filetype, str, -1, NULL); +} + +LIBTCCAPI int tcc_compile_string_file(TCCState *s, const char *str, const char *filename) +{ + return tcc_compile(s, s->filetype, str, -1, filename); +} + +/* define a preprocessor symbol. value can be NULL, sym can be "sym=val" */ +LIBTCCAPI void tcc_define_symbol(TCCState *s1, const char *sym, const char *value) +{ + const char *eq; + if (NULL == (eq = strchr(sym, '='))) + eq = strchr(sym, 0); + if (NULL == value) + value = *eq ? eq + 1 : "1"; + cstr_printf(&s1->cmdline_defs, "#define %.*s %s\n", (int)(eq-sym), sym, value); +} + +/* undefine a preprocessor symbol */ +LIBTCCAPI void tcc_undefine_symbol(TCCState *s1, const char *sym) +{ + cstr_printf(&s1->cmdline_defs, "#undef %s\n", sym); +} + + +LIBTCCAPI TCCState *tcc_new(void) +{ + TCCState *s; + + s = tcc_mallocz(sizeof(TCCState)); +#ifdef MEM_DEBUG + tcc_memcheck(1); +#endif + +#undef gnu_ext + s->gnu_ext = 1; + s->tcc_ext = 1; + s->nocommon = 1; + s->dollars_in_identifiers = 1; /*on by default like in gcc/clang*/ + s->cversion = 199901; /* default unless -std=c11 is supplied */ + s->warn_implicit_function_declaration = 1; + s->warn_discarded_qualifiers = 1; + s->ms_extensions = 1; + s->unwind_tables = 1; + +#ifdef CHAR_IS_UNSIGNED + s->char_is_unsigned = 1; +#endif +#ifdef TCC_TARGET_I386 + s->seg_size = 32; +#endif + /* enable this if you want symbols with leading underscore on windows: */ +#if defined TCC_TARGET_MACHO /* || defined TCC_TARGET_PE */ + s->leading_underscore = 1; +#endif +#ifdef TCC_TARGET_ARM + s->float_abi = ARM_FLOAT_ABI; +#endif +#ifdef CONFIG_NEW_DTAGS + s->enable_new_dtags = 1; +#endif + s->ppfp = stdout; + /* might be used in error() before preprocess_start() */ + s->include_stack_ptr = s->include_stack; + + tcc_set_lib_path(s, CONFIG_TCCDIR); +#ifdef CONFIG_TCC_SWITCHES /* predefined options */ + tcc_set_options(s, CONFIG_TCC_SWITCHES); +#endif + return s; +} + +LIBTCCAPI void tcc_delete(TCCState *s1) +{ + /* free sections */ + tccelf_delete(s1); + + /* free library paths */ + dynarray_reset(&s1->library_paths, &s1->nb_library_paths); + dynarray_reset(&s1->crt_paths, &s1->nb_crt_paths); + + /* free include paths */ + dynarray_reset(&s1->include_paths, &s1->nb_include_paths); + dynarray_reset(&s1->sysinclude_paths, &s1->nb_sysinclude_paths); + + tcc_free(s1->tcc_lib_path); + tcc_free(s1->soname); + tcc_free(s1->rpath); + tcc_free(s1->elfint); + tcc_free(s1->elf_entryname); + tcc_free(s1->init_symbol); + tcc_free(s1->fini_symbol); + tcc_free(s1->mapfile); + tcc_free(s1->outfile); + tcc_free(s1->deps_outfile); +#if defined TCC_TARGET_MACHO + tcc_free(s1->install_name); +#endif + dynarray_reset(&s1->files, &s1->nb_files); + dynarray_reset(&s1->target_deps, &s1->nb_target_deps); + dynarray_reset(&s1->pragma_libs, &s1->nb_pragma_libs); + dynarray_reset(&s1->argv, &s1->argc); + dynarray_reset(&s1->link_argv, &s1->link_argc); + cstr_free(&s1->cmdline_defs); + cstr_free(&s1->cmdline_incl); + tcc_free(s1->dState); +#ifdef TCC_IS_NATIVE + /* free runtime memory */ + tcc_run_free(s1); +#endif + /* free loaded dlls array */ + dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls); + tcc_free(s1); +#ifdef MEM_DEBUG + tcc_memcheck(-1); +#endif +} + +LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) +{ +#ifdef CONFIG_TCC_PIE + if (output_type == TCC_OUTPUT_EXE) + output_type |= TCC_OUTPUT_DYN; +#endif + s->output_type = output_type; + + if (!s->nostdinc) { + /* default include paths */ + /* -isystem paths have already been handled */ + tcc_add_sysinclude_path(s, CONFIG_TCC_SYSINCLUDEPATHS); + } + + if (output_type == TCC_OUTPUT_PREPROCESS) { + s->do_debug = 0; + return 0; + } + + /* add sections */ + tccelf_new(s); + + if (output_type == TCC_OUTPUT_OBJ) { + /* always elf for objects */ + s->output_format = TCC_OUTPUT_FORMAT_ELF; + return 0; + } + + if (!s->nostdlib_paths) + tcc_add_library_path(s, CONFIG_TCC_LIBPATHS); + +#ifdef TCC_TARGET_PE +# ifdef TCC_IS_NATIVE + /* allow linking with system dll's directly */ + tcc_add_systemdir(s); +# endif +#elif defined TCC_TARGET_MACHO +# ifdef TCC_IS_NATIVE + tcc_add_macos_sdkpath(s); +# endif +#else + /* paths for crt objects */ + tcc_split_path(s, &s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX); + if (output_type != TCC_OUTPUT_MEMORY && !s->nostdlib) + tccelf_add_crtbegin(s); +#endif + return 0; +} + +LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname) +{ + tcc_split_path(s, &s->include_paths, &s->nb_include_paths, pathname); + return 0; +} + +LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname) +{ + tcc_split_path(s, &s->sysinclude_paths, &s->nb_sysinclude_paths, pathname); + return 0; +} + +LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname) +{ + tcc_split_path(s, &s->library_paths, &s->nb_library_paths, pathname); + return 0; +} + +LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path) +{ + tcc_set_str(&s->tcc_lib_path, path); +} + +/* add/update a 'DLLReference', Just find if level == -1 */ +ST_FUNC DLLReference *tcc_add_dllref(TCCState *s1, const char *dllname, int level) +{ + DLLReference *ref = NULL; + int i; + for (i = 0; i < s1->nb_loaded_dlls; i++) + if (0 == strcmp(s1->loaded_dlls[i]->name, dllname)) { + ref = s1->loaded_dlls[i]; + break; + } + if (level == -1) + return ref; + if (ref) { + if (level < ref->level) + ref->level = level; + ref->found = 1; + return ref; + } + ref = tcc_mallocz(sizeof(DLLReference) + strlen(dllname)); + strcpy(ref->name, dllname); + dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, ref); + ref->level = level; + ref->index = s1->nb_loaded_dlls; + return ref; +} + +static int tcc_add_binary(TCCState *s1, int flags, const char *filename, int fd) +{ + ElfW(Ehdr) ehdr; + int obj_type; + const char *saved_filename = s1->current_filename; + int ret = 0; + + s1->current_filename = filename; + obj_type = tcc_object_type(fd, &ehdr); + lseek(fd, 0, SEEK_SET); + + switch (obj_type) { + + case AFF_BINTYPE_REL: + ret = tcc_load_object_file(s1, fd, 0); + break; + + case AFF_BINTYPE_AR: + ret = tcc_load_archive(s1, fd, !(flags & AFF_WHOLE_ARCHIVE)); + break; + +#if defined TCC_TARGET_UNIX + case AFF_BINTYPE_DYN: + if (s1->output_type == TCC_OUTPUT_MEMORY) { +#ifdef TCC_IS_NATIVE + void* dl = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY); + if (dl) + tcc_add_dllref(s1, filename, 0)->handle = dl; + else + ret = FILE_NOT_RECOGNIZED; +#endif + } else + ret = tcc_load_dll(s1, fd, filename, (flags & AFF_REFERENCED_DLL) != 0); + break; + + default: + /* as GNU ld, consider it is an ld script if not recognized */ + ret = tcc_load_ldscript(s1, fd); + break; + +#elif defined TCC_TARGET_MACHO + case AFF_BINTYPE_DYN: + case_dyn_or_tbd: + if (s1->output_type == TCC_OUTPUT_MEMORY) { +#ifdef TCC_IS_NATIVE + void* dl; + const char* soname = filename; + char *tmp = 0; + if (obj_type != AFF_BINTYPE_DYN) { + tmp = macho_tbd_soname(fd); + if (tmp) + soname = tmp; + } + dl = dlopen(soname, RTLD_GLOBAL | RTLD_LAZY); + if (dl) + tcc_add_dllref(s1, soname, 0)->handle = dl; + else + ret = FILE_NOT_RECOGNIZED; + tcc_free(tmp); +#endif + } else if (obj_type == AFF_BINTYPE_DYN) { + ret = macho_load_dll(s1, fd, filename, (flags & AFF_REFERENCED_DLL) != 0); + } else { + ret = macho_load_tbd(s1, fd, filename, (flags & AFF_REFERENCED_DLL) != 0); + } + if (ret) + ret = FILE_NOT_RECOGNIZED; + break; + + default: + { + const char *ext = tcc_fileextension(filename); + if (!strcmp(ext, ".tbd")) + goto case_dyn_or_tbd; + if (!strcmp(ext, ".dylib")) { + obj_type = AFF_BINTYPE_DYN; + goto case_dyn_or_tbd; + } + ret = FILE_NOT_RECOGNIZED; + break; + } + +#elif defined TCC_TARGET_PE + default: + if (pe_load_file(s1, fd, filename)) + ret = FILE_NOT_RECOGNIZED; + break; +#endif + +#ifdef TCC_TARGET_COFF + case AFF_BINTYPE_C67: + ret = tcc_load_coff(s1, fd); + break; +#endif + } + + close(fd); + s1->current_filename = saved_filename; + if (ret == FILE_NOT_RECOGNIZED) + return tcc_error_noabort("%s: unrecognized file type", filename); + return ret; +} + +/* OpenBSD: choose latest from libxxx.so.x.y versions */ +#if defined TARGETOS_OpenBSD && !defined _WIN32 +#include +static int tcc_glob_so(TCCState *s1, const char *pattern, char *buf, int size) +{ + const char *star; + glob_t g; + char *p; + int i, v, v1, v2, v3; + + star = strchr(pattern, '*'); + if (!star || glob(pattern, 0, NULL, &g)) + return -1; + for (v = -1, i = 0; i < g.gl_pathc; ++i) { + p = g.gl_pathv[i]; + if (2 != sscanf(p + (star - pattern), "%d.%d.%d", &v1, &v2, &v3)) + continue; + if ((v1 = v1 * 1000 + v2) > v) + v = v1, pstrcpy(buf, size, p); + } + globfree(&g); + return v; +} +#endif + +static int guess_filetype(const char *filename) +{ + int filetype = 0; + if (1) { + /* use a file extension to detect a filetype */ + const char *ext = tcc_fileextension(filename); + if (ext[0]) { + ext++; + if (!strcmp(ext, "S")) + filetype = AFF_TYPE_ASMPP; + else if (!strcmp(ext, "s")) + filetype = AFF_TYPE_ASM; + else if (!PATHCMP(ext, "c") + || !PATHCMP(ext, "h") + || !PATHCMP(ext, "i")) + filetype = AFF_TYPE_C; + else + filetype |= AFF_TYPE_BIN; + } else { + filetype = AFF_TYPE_C; + } + } + return filetype; +} + +ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) +{ + int fd; + +#if defined TARGETOS_OpenBSD && !defined _WIN32 + char buf[1024]; + if (tcc_glob_so(s1, filename, buf, sizeof buf) >= 0) + filename = buf; +#endif + + if (0 == (flags & AFF_TYPE_MASK)) + flags |= guess_filetype(filename); + + /* ignore binary files with -E */ + if (s1->output_type == TCC_OUTPUT_PREPROCESS + && (flags & AFF_TYPE_BIN)) + return 0; + + /* open the file */ + fd = _tcc_open(s1, filename); + if (fd < 0) { + if (flags & AFF_PRINT_ERROR) + tcc_error_noabort("file '%s' not found", filename); + return FILE_NOT_FOUND; + } + + if (flags & AFF_TYPE_BIN) + return tcc_add_binary(s1, flags, filename, fd); + + dynarray_add(&s1->target_deps, &s1->nb_target_deps, tcc_strdup(filename)); + return tcc_compile(s1, flags, filename, fd, NULL); +} + +LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename) +{ + return tcc_add_file_internal(s, filename, s->filetype | AFF_PRINT_ERROR); +} + +static int tcc_add_library_internal(TCCState *s1, const char *fmt, + const char *filename, int flags, char **paths, int nb_paths) +{ + char buf[1024]; + int i, ret; + + for(i = 0; i < nb_paths; i++) { + snprintf(buf, sizeof(buf), fmt, paths[i], filename); + ret = tcc_add_file_internal(s1, buf, flags & ~AFF_PRINT_ERROR); + if (ret != FILE_NOT_FOUND) + return ret; + } + if (flags & AFF_PRINT_ERROR) + tcc_error_noabort("%s '%s' not found", + flags & AFF_TYPE_LIB ? "library" : "file", filename); + return FILE_NOT_FOUND; +} + +/* find and load a dll. Return non zero if not found */ +ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags) +{ + return tcc_add_library_internal(s, "%s/%s", filename, flags, + s->library_paths, s->nb_library_paths); +} + +/* find [cross-]libtcc1.a and tcc helper objects in library path */ +ST_FUNC int tcc_add_support(TCCState *s1, const char *filename) +{ + char buf[100]; + if (CONFIG_TCC_CROSSPREFIX[0]) + filename = strcat(strcpy(buf, CONFIG_TCC_CROSSPREFIX), filename); + return tcc_add_dll(s1, filename, AFF_PRINT_ERROR); +} + +#ifdef TCC_TARGET_UNIX +ST_FUNC int tcc_add_crt(TCCState *s1, const char *filename) +{ + return tcc_add_library_internal(s1, "%s/%s", + filename, AFF_PRINT_ERROR, s1->crt_paths, s1->nb_crt_paths); +} +#endif + +/* the library name is the same as the argument of the '-l' option */ +LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname) +{ + static const char * const libs[] = { +#if defined TCC_TARGET_PE + "%s/%s.def", "%s/lib%s.def", "%s/%s.dll", "%s/lib%s.dll", +#elif defined TCC_TARGET_MACHO + "%s/lib%s.dylib", "%s/lib%s.tbd", +#elif defined TARGETOS_OpenBSD + "%s/lib%s.so.*", +#else + "%s/lib%s.so", +#endif + "%s/lib%s.a", + NULL + }; + int flags = AFF_TYPE_LIB | (s->filetype & AFF_WHOLE_ARCHIVE); + /* if libraryname begins with a colon, it means search lib paths for + exactly the following file, without lib prefix or anything */ + if (*libraryname == ':') { + libraryname++; + } else { + const char * const *pp = libs; + if (s->static_link) + pp += sizeof(libs) / sizeof(*libs) - 2; /* only "%s/lib%s.a" */ + while (*pp) { + int ret = tcc_add_library_internal(s, *pp, + libraryname, flags, s->library_paths, s->nb_library_paths); + if (ret != FILE_NOT_FOUND) + return ret; + ++pp; + } + } + /* fallback to try file without pre- or sufffix */ + return tcc_add_dll(s, libraryname, flags | AFF_PRINT_ERROR); +} + +/* handle #pragma comment(lib,) */ +ST_FUNC void tcc_add_pragma_libs(TCCState *s1) +{ + int i; + for (i = 0; i < s1->nb_pragma_libs; i++) + tcc_add_library(s1, s1->pragma_libs[i]); +} + +/********************************************************/ +/* options parser */ + +static int strstart(const char *val, const char **str) +{ + const char *p, *q; + p = *str; + q = val; + while (*q) { + if (*p != *q) + return 0; + p++; + q++; + } + *str = p; + return 1; +} + +struct lopt { + TCCState *s; + const char *opt, *arg; + int match; +}; + +/* match linker option */ +static int link_option(struct lopt *o, const char *q) +{ + const char *p = o->opt; + int c; + + /* there should be 1 or 2 dashes */ + if (*p++ != '-') + return 0; + if (*p == '-') + p++; + while ((c = *q) == *p) { + if (c == '\0') + goto succ; /* -Wl,-opt */ + ++p; + if (c == '=') + goto succ; /* -Wl,-opt=arg */ + ++q; + } + if (c == '=' || c == ':') { + if (*p == '\0') { + if (o->s->link_optind + 1 < o->s->link_argc) { + p = o->s->link_argv[++o->s->link_optind]; + goto succ; /* -Wl,-opt,arg */ + } + o->match = 1; /* -Wl,-opt -Wl,arg */ + } else if (c == ':') + goto succ; /* -Wl,-Iarg */ + } + return 0; +succ: + o->arg = p; + //printf("set %s '%s'\n", o->opt, o->arg); + return 1; +} + +static void args_parser_add_file(TCCState *s, const char* filename, int filetype); + +/* set linker options */ +static int tcc_set_linker(TCCState *s, const char *optarg) +{ + TCCState *s1 = s; + + dynarray_split(&s1->link_argv, &s1->link_argc, optarg, ','); + + while (s->link_optind < s->link_argc) { + char *end = NULL; + int ignoring = 0; + struct lopt o = {0}; + o.s = s; + o.opt = s->link_argv[s->link_optind]; + + if (link_option(&o, "Bsymbolic")) { + s->symbolic = 1; + } else if (link_option(&o, "nostdlib")) { + s->nostdlib_paths = 1; + } else if (link_option(&o, "e=") || link_option(&o, "entry=")) { + tcc_set_str(&s->elf_entryname, o.arg); + } else if (link_option(&o, "image-base=") || link_option(&o, "Ttext=")) { + s->text_addr = strtoull(o.arg, &end, 16); + s->has_text_addr = 1; + } else if (link_option(&o, "init=")) { + tcc_set_str(&s->init_symbol, o.arg); + ignoring = 1; + } else if (link_option(&o, "fini=")) { + tcc_set_str(&s->fini_symbol, o.arg); + ignoring = 1; + } else if (link_option(&o, "Map=")) { + tcc_set_str(&s->mapfile, o.arg); + ignoring = 1; + } else if (link_option(&o, "oformat=")) { +#if defined TCC_TARGET_PE + if (0 == strncmp("pe-", o.arg, 3)) +#elif PTR_SIZE == 8 + if (0 == strncmp("elf64-", o.arg, 6)) +#else + if (0 == strncmp("elf32-", o.arg, 6)) +#endif + s->output_format = TCC_OUTPUT_FORMAT_ELF; + else if (0==strcmp("binary", o.arg)) + s->output_format = TCC_OUTPUT_FORMAT_BINARY; +#if defined TCC_TARGET_COFF + else if (0==strcmp("coff", o.arg)) + s->output_format = TCC_OUTPUT_FORMAT_COFF; +#endif + else + goto err; + } else if (link_option(&o, "export-all-symbols") + || link_option(&o, "export-dynamic")) { + s->rdynamic = 1; + } else if (link_option(&o, "rpath=")) { + tcc_concat_str(&s->rpath, o.arg, ':'); + } else if (link_option(&o, "dynamic-linker=") || link_option(&o, "I:")) { + tcc_set_str(&s->elfint, o.arg); + } else if (link_option(&o, "enable-new-dtags")) { + s->enable_new_dtags = 1; + } else if (link_option(&o, "section-alignment=")) { + s->section_align = strtoul(o.arg, &end, 16); + } else if (link_option(&o, "soname=") || link_option(&o, "install_name=")) { + tcc_set_str(&s->soname, o.arg); + } else if (link_option(&o, "whole-archive")) { + s->filetype |= AFF_WHOLE_ARCHIVE; + } else if (link_option(&o, "no-whole-archive")) { + s->filetype &= ~AFF_WHOLE_ARCHIVE; + } else if (link_option(&o, "znodelete")) { + s->znodelete = 1; +#ifdef TCC_TARGET_PE + } else if (link_option(&o, "large-address-aware")) { + s->pe_characteristics |= 0x20; + } else if (link_option(&o, "file-alignment=")) { + s->pe_file_align = strtoul(o.arg, &end, 16); + } else if (link_option(&o, "stack=")) { + s->pe_stack_size = strtoul(o.arg, &end, 10); + } else if (link_option(&o, "subsystem=")) { + if (pe_setsubsy(s, o.arg) < 0) + goto err; +#elif defined TCC_TARGET_MACHO + } else if (link_option(&o, "all_load")) { + s->filetype |= AFF_WHOLE_ARCHIVE; + } else if (link_option(&o, "force_load=")) { + args_parser_add_file(s, o.arg, AFF_TYPE_LIB | AFF_WHOLE_ARCHIVE); + } else if (link_option(&o, "single_module")) { + ignoring = 1; +#endif + } else if (link_option(&o, "as-needed")) { + ignoring = 1; + } else if (link_option(&o, "O")) { + ignoring = 1; + } else if (link_option(&o, "z=")) { + ignoring = 1; + } else if (link_option(&o, "L:")) { + tcc_add_library_path(s, o.arg); + } else if (link_option(&o, "l:")) { + args_parser_add_file(s, o.arg, AFF_TYPE_LIB | (s->filetype & ~AFF_TYPE_MASK)); + } else if (o.match) { + return 0; /* expecting argument with next '-Wl,' */ + } else { + err: + return tcc_error_noabort("unsupported linker option '%s'", o.opt); + } + if (ignoring) + tcc_warning_c(warn_unsupported)("unsupported linker option '%s'", o.opt); + ++s->link_optind; + } + return 0; +} + +typedef struct TCCOption { + const char *name; + uint16_t index; + uint16_t flags; +} TCCOption; + +enum { + TCC_OPTION_ignored = 0, + TCC_OPTION_HELP, + TCC_OPTION_HELP2, + TCC_OPTION_v, + TCC_OPTION_I, + TCC_OPTION_D, + TCC_OPTION_U, + TCC_OPTION_P, + TCC_OPTION_L, + TCC_OPTION_B, + TCC_OPTION_l, + TCC_OPTION_bench, + TCC_OPTION_bt, + TCC_OPTION_b, + TCC_OPTION_g, + TCC_OPTION_c, + TCC_OPTION_dumpmachine, + TCC_OPTION_dumpversion, + TCC_OPTION_d, + TCC_OPTION_static, + TCC_OPTION_std, + TCC_OPTION_shared, + TCC_OPTION_soname, + TCC_OPTION_o, + TCC_OPTION_r, + TCC_OPTION_Wl, + TCC_OPTION_Wp, + TCC_OPTION_W, + TCC_OPTION_O, + TCC_OPTION_mfloat_abi, + TCC_OPTION_m, + TCC_OPTION_f, + TCC_OPTION_isystem, + TCC_OPTION_iwithprefix, + TCC_OPTION_include, + TCC_OPTION_nostdinc, + TCC_OPTION_nostdlib, + TCC_OPTION_print_search_dirs, + TCC_OPTION_rdynamic, + TCC_OPTION_pthread, + TCC_OPTION_run, + TCC_OPTION_rstdin, + TCC_OPTION_w, + TCC_OPTION_E, + TCC_OPTION_M, + TCC_OPTION_MD, + TCC_OPTION_MF, + TCC_OPTION_MM, + TCC_OPTION_MMD, + TCC_OPTION_MP, + TCC_OPTION_x, + TCC_OPTION_ar, + TCC_OPTION_impdef, + /* macho */ + TCC_OPTION_dynamiclib, + TCC_OPTION_flat_namespace, + TCC_OPTION_two_levelnamespace, + TCC_OPTION_undefined, + TCC_OPTION_install_name, + TCC_OPTION_compatibility_version , + TCC_OPTION_current_version, +}; + +#define TCC_OPTION_HAS_ARG 0x0001 +#define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */ + +/* + * in tcc_options, if opt-string A is a prefix of opt-string B, + * it's un-ambiguous if and only if option A is without TCC_OPTION_HAS_ARG. + * otherwise (A with HAS_ARG), if, for instance, A is FOO and B is FOOBAR, + * then "-FOOBAR" is either A with arg BAR, or B (-FOOBARX too, if B HAS_ARG). + * + * tcc_parse_args searches tcc_options in order, so if ambiguous: + * - if the shorter (A) is earlier: the longer (B) is completely unreachable. + * - else B wins, and A can't be used with adjacent arg if it also matches B. + * + * there are few clashes currently, and the longer is always earlier/reachable. + * when it's ambiguous, shorter-concat-arg is not useful currently. + * the sh(1) script 'optclash' can identifiy clashes (tcc root dir, try "-h"). + * at the time of writing, running './optclash' prints this: + + -Wl,... (1642) overrides -W... (1644) + -Wp,... (1643) overrides -W... (1644) + -dumpmachine (1630) overrides -d... (1632) + -dumpversion (1631) overrides -d... (1632) + -dynamiclib (1623) overrides -d... (1632) + -flat_namespace (1624) overrides -f... (1650) + -mfloat-abi... (1647) overrides -m... (1649) + + */ +static const TCCOption tcc_options[] = { + { "h", TCC_OPTION_HELP, 0 }, + { "-help", TCC_OPTION_HELP, 0 }, + { "?", TCC_OPTION_HELP, 0 }, + { "hh", TCC_OPTION_HELP2, 0 }, + { "v", TCC_OPTION_v, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "-version", TCC_OPTION_v, 0 }, /* handle as verbose, also prints version*/ + { "I", TCC_OPTION_I, TCC_OPTION_HAS_ARG }, + { "D", TCC_OPTION_D, TCC_OPTION_HAS_ARG }, + { "U", TCC_OPTION_U, TCC_OPTION_HAS_ARG }, + { "P", TCC_OPTION_P, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "L", TCC_OPTION_L, TCC_OPTION_HAS_ARG }, + { "B", TCC_OPTION_B, TCC_OPTION_HAS_ARG }, + { "l", TCC_OPTION_l, TCC_OPTION_HAS_ARG }, + { "bench", TCC_OPTION_bench, 0 }, +#ifdef CONFIG_TCC_BACKTRACE + { "bt", TCC_OPTION_bt, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, +#endif +#ifdef CONFIG_TCC_BCHECK + { "b", TCC_OPTION_b, 0 }, +#endif + { "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, +#ifdef TCC_TARGET_MACHO + { "compatibility_version", TCC_OPTION_compatibility_version, TCC_OPTION_HAS_ARG }, + { "current_version", TCC_OPTION_current_version, TCC_OPTION_HAS_ARG }, + { "dynamiclib", TCC_OPTION_dynamiclib, 0 }, + { "flat_namespace", TCC_OPTION_flat_namespace, 0 }, + { "install_name", TCC_OPTION_install_name, TCC_OPTION_HAS_ARG }, + { "two_levelnamespace", TCC_OPTION_two_levelnamespace, 0 }, + { "undefined", TCC_OPTION_undefined, TCC_OPTION_HAS_ARG }, +#endif + { "c", TCC_OPTION_c, 0 }, + { "dumpmachine", TCC_OPTION_dumpmachine, 0}, + { "dumpversion", TCC_OPTION_dumpversion, 0}, + { "d", TCC_OPTION_d, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "static", TCC_OPTION_static, 0 }, + { "std", TCC_OPTION_std, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "shared", TCC_OPTION_shared, 0 }, + { "soname", TCC_OPTION_soname, TCC_OPTION_HAS_ARG }, + { "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG }, + { "pthread", TCC_OPTION_pthread, 0}, + { "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "rstdin", TCC_OPTION_rstdin, TCC_OPTION_HAS_ARG }, + { "rdynamic", TCC_OPTION_rdynamic, 0 }, + { "r", TCC_OPTION_r, 0 }, + { "Wl,", TCC_OPTION_Wl, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "Wp,", TCC_OPTION_Wp, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "O", TCC_OPTION_O, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, +#ifdef TCC_TARGET_ARM + { "mfloat-abi", TCC_OPTION_mfloat_abi, TCC_OPTION_HAS_ARG }, +#endif + { "m", TCC_OPTION_m, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "f", TCC_OPTION_f, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "isystem", TCC_OPTION_isystem, TCC_OPTION_HAS_ARG }, + { "include", TCC_OPTION_include, TCC_OPTION_HAS_ARG }, + { "nostdinc", TCC_OPTION_nostdinc, 0 }, + { "nostdlib", TCC_OPTION_nostdlib, 0 }, + { "print-search-dirs", TCC_OPTION_print_search_dirs, 0 }, + { "w", TCC_OPTION_w, 0 }, + { "E", TCC_OPTION_E, 0}, + { "M", TCC_OPTION_M, 0}, + { "MM", TCC_OPTION_MM, 0}, + { "MD", TCC_OPTION_MD, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "MMD", TCC_OPTION_MMD, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP }, + { "MF", TCC_OPTION_MF, TCC_OPTION_HAS_ARG }, + { "MP", TCC_OPTION_MP, 0}, + { "x", TCC_OPTION_x, TCC_OPTION_HAS_ARG }, + /* tcctools */ + { "ar", TCC_OPTION_ar, 0}, +#ifdef TCC_TARGET_PE + { "impdef", TCC_OPTION_impdef, 0}, +#endif + /* ignored (silently, except after -Wunsupported) */ + { "arch", 0, TCC_OPTION_HAS_ARG}, + { "C", 0, 0 }, + { "-param", 0, TCC_OPTION_HAS_ARG }, + { "pedantic", 0, 0 }, + { "pie", 0, 0 }, + { "pipe", 0, 0 }, + { "s", 0, 0 }, + { "traditional", 0, 0 }, + { NULL, 0, 0 }, +}; + +typedef struct FlagDef { + uint16_t offset; + uint16_t flags; + const char *name; +} FlagDef; + +#define WD_ALL 0x0001 /* warning is activated when using -Wall */ +#define FD_INVERT 0x0002 /* invert value before storing */ + +static const FlagDef options_W[] = { + { offsetof(TCCState, warn_all), WD_ALL, "all" }, + { offsetof(TCCState, warn_error), 0, "error" }, + { offsetof(TCCState, warn_write_strings), 0, "write-strings" }, + { offsetof(TCCState, warn_unsupported), 0, "unsupported" }, + { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL, "implicit-function-declaration" }, + { offsetof(TCCState, warn_discarded_qualifiers), WD_ALL, "discarded-qualifiers" }, + { 0, 0, NULL } +}; + +static const FlagDef options_f[] = { + { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" }, + { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" }, + { offsetof(TCCState, nocommon), FD_INVERT, "common" }, + { offsetof(TCCState, leading_underscore), 0, "leading-underscore" }, + { offsetof(TCCState, ms_extensions), 0, "ms-extensions" }, + { offsetof(TCCState, dollars_in_identifiers), 0, "dollars-in-identifiers" }, + { offsetof(TCCState, test_coverage), 0, "test-coverage" }, + { offsetof(TCCState, reverse_funcargs), 0, "reverse-funcargs" }, + { offsetof(TCCState, gnu89_inline), 0, "gnu89-inline" }, + { offsetof(TCCState, unwind_tables), 0, "asynchronous-unwind-tables" }, + { 0, 0, NULL } +}; + +static const FlagDef options_m[] = { + { offsetof(TCCState, ms_bitfields), 0, "ms-bitfields" }, +#ifdef TCC_TARGET_X86_64 + { offsetof(TCCState, nosse), FD_INVERT, "sse" }, +#endif + { 0, 0, NULL } +}; + +static int set_flag(TCCState *s, const FlagDef *flags, const char *name) +{ + int value, mask, ret; + const FlagDef *p; + const char *r; + unsigned char *f; + + r = name, value = !strstart("no-", &r), mask = 0; + + /* when called with options_W, look for -W[no-]error=