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 8955356..e5031b4 100644 Binary files a/programs/lib/libc/obj/libc.o and b/programs/lib/libc/obj/libc.o differ 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=