feat: Intel GPU fixes, add tcc compiler, spreadsheet improvements, paint app, file manager improvements

This commit is contained in:
2026-03-21 17:35:16 +01:00
parent 2fd9b7d027
commit 770dde5001
72 changed files with 45499 additions and 305 deletions
+76 -7
View File
@@ -107,15 +107,36 @@ namespace Drivers::Graphics::IntelGPU {
<< " at PCI " << (uint64_t)found->Bus << ":" << " at PCI " << (uint64_t)found->Bus << ":"
<< (uint64_t)found->Device << "." << (uint64_t)found->Function; << (uint64_t)found->Device << "." << (uint64_t)found->Function;
} else { } else {
// Unknown device ID - accept generically but warn // Unknown device ID - infer generation from device ID range.
g_gpuInfo.gen = 7; // Assume gen 7 as a safe default // 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"; g_gpuInfo.name = "Intel GPU";
KernelLogStream(WARNING, "IntelGPU") << "Unknown Intel display controller " KernelLogStream(WARNING, "IntelGPU") << "Unknown Intel display controller "
<< "(device " << base::hex << (uint64_t)found->DeviceId << ")" << "(device " << base::hex << (uint64_t)found->DeviceId << ")"
<< " at PCI " << (uint64_t)found->Bus << ":" << " at PCI " << (uint64_t)found->Bus << ":"
<< (uint64_t)found->Device << "." << (uint64_t)found->Function << (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; g_gpuGen = g_gpuInfo.gen;
@@ -494,13 +515,32 @@ namespace Drivers::Graphics::IntelGPU {
<< " at PCI " << (uint64_t)dev.Bus << ":" << " at PCI " << (uint64_t)dev.Bus << ":"
<< (uint64_t)dev.Device << "." << (uint64_t)dev.Function; << (uint64_t)dev.Device << "." << (uint64_t)dev.Function;
} else { } 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"; g_gpuInfo.name = "Intel GPU";
KernelLogStream(WARNING, "IntelGPU") << "Unknown Intel display controller " KernelLogStream(WARNING, "IntelGPU") << "Unknown Intel display controller "
<< "(device " << base::hex << (uint64_t)dev.DeviceId << ")" << "(device " << base::hex << (uint64_t)dev.DeviceId << ")"
<< " at PCI " << (uint64_t)dev.Bus << ":" << " at PCI " << (uint64_t)dev.Bus << ":"
<< (uint64_t)dev.Device << "." << (uint64_t)dev.Function << (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; g_gpuGen = g_gpuInfo.gen;
@@ -643,14 +683,35 @@ namespace Drivers::Graphics::IntelGPU {
void Reinitialize() { void Reinitialize() {
if (!g_initialized || !g_mmioBase) return; 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 // 1. Re-enable PCI memory space and bus mastering. S3 resets the PCI
// command register, so MMIO writes to the GPU are silently dropped // command register, so MMIO writes to the GPU are silently dropped
// until we re-enable these bits. // until we re-enable these bits.
Pci::EnableBusMaster(g_gpuInfo.pciBus, g_gpuInfo.pciDevice, g_gpuInfo.pciFunction); 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) // 2. Disable VGA plane (firmware may have re-enabled it during POST)
DisableVga(); DisableVga();
@@ -673,6 +734,9 @@ namespace Drivers::Graphics::IntelGPU {
(void)gtt32[pageCount - 1]; (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 // 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 // though the firmware lit the backlight. Wait for it to become
// active before programming the display plane. // active before programming the display plane.
@@ -686,6 +750,11 @@ namespace Drivers::Graphics::IntelGPU {
break; break;
asm volatile("pause"); 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 // 5. Reprogram display plane to point at our GTT-mapped framebuffer
+16
View File
@@ -111,6 +111,22 @@ namespace Drivers::Graphics::IntelGPU {
{0x4680, 12, "Alder Lake-S GT1"}, {0x4680, 12, "Alder Lake-S GT1"},
{0x4692, 12, "Alder Lake-S GT1"}, {0x4692, 12, "Alder Lake-S GT1"},
{0x46A6, 12, "Alder Lake-P GT2"}, {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]); static constexpr int SupportedDeviceCount = sizeof(SupportedDevices) / sizeof(SupportedDevices[0]);
+19 -4
View File
@@ -59,7 +59,7 @@ BINDIR := bin
PROGRAMS := $(notdir $(wildcard src/*)) PROGRAMS := $(notdir $(wildcard src/*))
# Programs with custom Makefiles (built separately). # 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)) SYSTEM_PROGRAMS := $(filter-out $(CUSTOM_BUILDS),$(PROGRAMS))
# Build targets: system programs go to bin/os/, apps go to bin/apps/<name>/. # Build targets: system programs go to bin/os/, apps go to bin/apps/<name>/.
@@ -81,9 +81,9 @@ CA_CERTS := $(BINDIR)/etc/ca-certificates.crt
# Common shared assets (wallpapers, etc.) # Common shared assets (wallpapers, etc.)
COMMONKEEP := $(BINDIR)/common/.keep 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). # 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) BEARSSL_INCLUDES := -isystem $(shell cd .. && pwd)/kernel/freestnd-c-hdrs/x86_64/include -isystem $(abspath include/libc)
@@ -184,6 +184,10 @@ icons:
fonts: fonts:
../scripts/copy_fonts.sh ../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). # Build RPG demo game via its own Makefile (depends on libc).
rpgdemo: libc rpgdemo: libc
$(MAKE) -C src/rpgdemo $(MAKE) -C src/rpgdemo
@@ -192,8 +196,17 @@ rpgdemo: libc
doom: doom:
$(MAKE) -C src/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/<name>/. # Install app bundles (manifests, icons, data files) into bin/apps/<name>/.
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 ../scripts/install_apps.sh
# Copy man pages into bin/man/ so mkramdisk.sh picks them up. # 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/volume clean
$(MAKE) -C src/music clean $(MAKE) -C src/music clean
$(MAKE) -C src/bluetooth clean $(MAKE) -C src/bluetooth clean
$(MAKE) -C src/paint clean
$(MAKE) -C src/rpgdemo clean $(MAKE) -C src/rpgdemo clean
$(MAKE) -C src/tcc clean
+14
View File
@@ -95,6 +95,20 @@ struct DesktopState {
SvgIcon icon_drive; SvgIcon icon_drive;
SvgIcon icon_drive_lg; SvgIcon icon_drive_lg;
SvgIcon icon_delete; 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_settings;
SvgIcon icon_reboot; SvgIcon icon_reboot;
+63 -11
View File
@@ -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; 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) // 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); 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 // Extract and rasterize path
int d_len = svg_get_attr(elem_start, elem_len, " d", d_buf, SVG_MAX_PATH_LEN); int d_len = svg_get_attr(elem_start, elem_len, " d", d_buf, SVG_MAX_PATH_LEN);
if (d_len > 0) { if (d_len > 0) {
el.clear(); 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) if (el.count > 0)
svg_rasterize_blend(el, icon.pixels, target_w, target_h, elem_color.to_pixel(), alpha); 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); 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]; char attr_buf[32];
fixed_t cx = 0, cy = 0, r = 0; fixed_t cx = 0, cy = 0, r = 0;
if (svg_get_attr(elem_start, elem_len, " cx", attr_buf, sizeof(attr_buf)) > 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) if (svg_get_attr(elem_start, elem_len, " r", attr_buf, sizeof(attr_buf)) > 0)
svg_parse_fixed(attr_buf, &r); svg_parse_fixed(attr_buf, &r);
fixed_t scx = fixed_mul(cx - vb_x, scale_x); fixed_t scx = fixed_mul(cx - vb_x, eff_sx);
fixed_t scy = fixed_mul(cy - vb_y, scale_y); fixed_t scy = fixed_mul(cy - vb_y, eff_sy);
fixed_t srx = fixed_mul(r, scale_x); fixed_t srx = fixed_mul(r, eff_sx);
fixed_t sry = fixed_mul(r, scale_y); fixed_t sry = fixed_mul(r, eff_sy);
fixed_t sr = (srx + sry) >> 1; fixed_t sr = (srx + sry) >> 1;
el.clear(); 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); 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]; char attr_buf[32];
fixed_t rx_val = 0, ry_val = 0, rw = 0, rh = 0, rrx = 0, rry = 0; 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) if (svg_get_attr(elem_start, elem_len, " ry", attr_buf, sizeof(attr_buf)) > 0)
svg_parse_fixed(attr_buf, &rry); svg_parse_fixed(attr_buf, &rry);
fixed_t sx = fixed_mul(rx_val - vb_x, scale_x); fixed_t sx = fixed_mul(rx_val - vb_x, eff_sx);
fixed_t sy = fixed_mul(ry_val - vb_y, scale_y); fixed_t sy = fixed_mul(ry_val - vb_y, eff_sy);
fixed_t sw = fixed_mul(rw, scale_x); fixed_t sw = fixed_mul(rw, eff_sx);
fixed_t sh = fixed_mul(rh, scale_y); fixed_t sh = fixed_mul(rh, eff_sy);
fixed_t srx = fixed_mul(rrx, scale_x); fixed_t srx = fixed_mul(rrx, eff_sx);
fixed_t sry = fixed_mul(rry, scale_y); fixed_t sry = fixed_mul(rry, eff_sy);
el.clear(); el.clear();
svg_rect_edges(el, sx, sy, sw, sh, srx, sry); svg_rect_edges(el, sx, sy, sw, sh, srx, sry);
+580
View File
@@ -0,0 +1,580 @@
/*
* montauk.h
* MontaukOS C API for user programs (TCC-compatible)
* Copyright (c) 2026 Daniel Hammer
*
* Usage: #include <montauk.h>
*
* 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 <stdint.h>
#include <stddef.h>
#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 */
+1
View File
@@ -12,6 +12,7 @@ extern "C" {
int read(int fd, void *buf, size_t count); int read(int fd, void *buf, size_t count);
int write(int fd, const void *buf, size_t count); int write(int fd, const void *buf, size_t count);
int close(int fd); int close(int fd);
long lseek(int fd, long offset, int whence);
#ifdef __cplusplus #ifdef __cplusplus
} }
+663 -2
View File
@@ -9,6 +9,10 @@
#include <stdint.h> #include <stdint.h>
#include <stdarg.h> #include <stdarg.h>
#include <limits.h> #include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
/* ======================================================================== /* ========================================================================
Raw syscall wrappers (C versions matching kernel ABI) Raw syscall wrappers (C versions matching kernel ABI)
@@ -32,6 +36,31 @@ static inline long _zos_syscall1(long nr, long a1) {
return ret; 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) { static inline long _zos_syscall4(long nr, long a1, long a2, long a3, long a4) {
long ret; long ret;
__asm__ volatile( __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_EXIT 0
#define SYS_PRINT 4 #define SYS_PRINT 4
#define SYS_PUTCHAR 5 #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_ALLOC 11
#define SYS_FREE 12 #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 errno
@@ -596,8 +638,11 @@ void abort(void) {
} }
int system(const char *command) { int system(const char *command) {
(void)command; if (command == NULL) return -1;
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; (void)line; (void)func;
abort(); 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);
}
Binary file not shown.
File diff suppressed because it is too large Load Diff
+329 -49
View File
@@ -11,14 +11,15 @@
// Text Editor state // Text Editor state
// ============================================================================ // ============================================================================
static constexpr int TE_TOOLBAR_H = 36; static constexpr int TE_TOOLBAR_H = 36;
static constexpr int TE_PATHBAR_H = 32; static constexpr int TE_PATHBAR_H = 32;
static constexpr int TE_STATUS_H = 24; static constexpr int TE_STATUS_H = 24;
static constexpr int TE_LINE_NUM_W = 48; static constexpr int TE_LINE_NUM_W = 48;
static constexpr int TE_INIT_CAP = 4096; static constexpr int TE_SCROLLBAR_W = 12;
static constexpr int TE_MAX_CAP = 262144; // 256KB static constexpr int TE_INIT_CAP = 4096;
static constexpr int TE_MAX_LINES = 16384; static constexpr int TE_MAX_CAP = 262144; // 256KB
static constexpr int TE_TAB_WIDTH = 4; static constexpr int TE_MAX_LINES = 16384;
static constexpr int TE_TAB_WIDTH = 4;
struct TextEditorState { struct TextEditorState {
char* buffer; char* buffer;
@@ -32,10 +33,20 @@ struct TextEditorState {
int scroll_y; // first visible line int scroll_y; // first visible line
int scroll_x; // horizontal scroll in pixels int scroll_x; // horizontal scroll in pixels
bool modified; bool modified;
bool cursor_moved; // set when cursor moves, triggers scroll-to-cursor
char filepath[256]; char filepath[256];
char filename[64]; char filename[64];
DesktopState* desktop; 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; bool show_pathbar;
char pathbar_text[256]; char pathbar_text[256];
int pathbar_cursor; 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_col = te->cursor_pos - te->line_offsets[te->cursor_line];
te->cursor_moved = true;
} }
static int te_line_length(TextEditorState* te, int line) { 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); 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 // 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) { if (te->cursor_line < te->scroll_y) {
te->scroll_y = te->cursor_line; 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; 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 // Horizontal scroll
int cell_w = mono_cell_width(); int cell_w = mono_cell_width();
int cursor_px = te->cursor_col * cell_w; 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) { if (cursor_px - te->scroll_x > view_w - cell_w * 2) {
te->scroll_x = cursor_px - view_w + cell_w * 4; 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 text_area_h = c.h - editor_y_start - TE_STATUS_H;
int visible_lines = text_area_h / cell_h; int visible_lines = text_area_h / cell_h;
if (visible_lines < 1) visible_lines = 1; 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 // Line number gutter background
c.fill_rect(0, editor_y_start, TE_LINE_NUM_W, text_area_h, Color::from_rgb(0xF0, 0xF0, 0xF0)); 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 // Gutter separator
c.vline(TE_LINE_NUM_W, editor_y_start, text_area_h, colors::BORDER); 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 // Draw lines
Color linenum_color = Color::from_rgb(0x99, 0x99, 0x99); Color linenum_color = Color::from_rgb(0x99, 0x99, 0x99);
Color cursor_line_color = Color::from_rgb(0xFF, 0xFD, 0xE8); 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; int py = editor_y_start + vis * cell_h;
if (py >= editor_y_start + text_area_h) break; if (py >= editor_y_start + text_area_h) break;
// Cursor line highlighting // Cursor line highlighting (only when no selection)
if (line == te->cursor_line) { if (line == te->cursor_line && !te->has_selection) {
int hl_h = gui_min(cell_h, editor_y_start + text_area_h - py); int hl_h = gui_min(cell_h, editor_y_start + text_area_h - py);
if (hl_h > 0) 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 // Line number
@@ -417,9 +510,18 @@ static void texteditor_on_draw(Window* win, Framebuffer& fb) {
for (int ci = 0; ci < line_len; ci++) { for (int ci = 0; ci < line_len; ci++) {
int px = text_start_x + ci * cell_w - te->scroll_x; int px = text_start_x + ci * cell_w - te->scroll_x;
if (px + cell_w <= TE_LINE_NUM_W + 1) continue; 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 (ch >= 32 || ch < 0) {
if (fonts::mono && fonts::mono->valid) { if (fonts::mono && fonts::mono->valid) {
GlyphCache* gc = fonts::mono->get_cache(fonts::TERM_SIZE); 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)) { if (bits & (0x80 >> fx)) {
int dx = px + fx; int dx = px + fx;
int dy = py + fy; 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; 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 // Draw cursor
if (line == te->cursor_line) { if (line == te->cursor_line) {
int cx = text_start_x + te->cursor_col * cell_w - te->scroll_x; 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); int cur_h = gui_min(cell_h, editor_y_start + text_area_h - py);
if (cur_h > 0) if (cur_h > 0)
c.fill_rect(cx, py, 2, cur_h, colors::ACCENT); 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 ---- // ---- Status bar ----
int status_y = c.h - TE_STATUS_H; 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)); c.fill_rect(0, status_y, c.w, TE_STATUS_H, Color::from_rgb(0x2B, 0x3E, 0x50));
// Cursor position (right side) // Cursor position (right side)
char status_right[32]; char status_right[48];
snprintf(status_right, 32, "Ln %d, Col %d ", te->cursor_line + 1, te->cursor_col + 1); 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 sr_w = text_width(status_right);
int status_text_y = status_y + (TE_STATUS_H - sfh) / 2; 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); 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 // 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) { static void texteditor_on_mouse(Window* win, MouseEvent& ev) {
TextEditorState* te = (TextEditorState*)win->app_data; TextEditorState* te = (TextEditorState*)win->app_data;
if (!te) return; 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_x = ev.x - cr.x;
int local_y = ev.y - cr.y; int local_y = ev.y - cr.y;
int cell_w = mono_cell_width();
int cell_h = mono_cell_height(); int cell_h = mono_cell_height();
int editor_y_start = TE_TOOLBAR_H + (te->show_pathbar ? TE_PATHBAR_H : 0); 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; 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 ---- // ---- Toolbar clicks ----
if (ev.left_pressed() && local_y < TE_TOOLBAR_H) { if (ev.left_pressed() && local_y < TE_TOOLBAR_H) {
// Open button // Open button
if (local_x >= 4 && local_x < 28 && local_y >= 6 && local_y < 30) { if (local_x >= 4 && local_x < 28 && local_y >= 6 && local_y < 30) {
te->show_pathbar = !te->show_pathbar; te->show_pathbar = !te->show_pathbar;
if (te->show_pathbar) { if (te->show_pathbar) {
// Pre-fill with current filepath
montauk::strncpy(te->pathbar_text, te->filepath, 255); montauk::strncpy(te->pathbar_text, te->filepath, 255);
te->pathbar_len = montauk::slen(te->pathbar_text); te->pathbar_len = montauk::slen(te->pathbar_text);
te->pathbar_cursor = te->pathbar_len; te->pathbar_cursor = te->pathbar_len;
@@ -519,14 +683,12 @@ static void texteditor_on_mouse(Window* win, MouseEvent& ev) {
// ---- Path bar clicks ---- // ---- Path bar clicks ----
if (te->show_pathbar && local_y >= TE_TOOLBAR_H && local_y < TE_TOOLBAR_H + TE_PATHBAR_H) { if (te->show_pathbar && local_y >= TE_TOOLBAR_H && local_y < TE_TOOLBAR_H + TE_PATHBAR_H) {
if (ev.left_pressed()) { if (ev.left_pressed()) {
// Check "Open" button region
int btn_w = 56; int btn_w = 56;
int inp_w = cr.w - 8 - btn_w - 12; int inp_w = cr.w - 8 - btn_w - 12;
int ob_x = 8 + inp_w + 6; int ob_x = 8 + inp_w + 6;
if (local_x >= ob_x && local_x < ob_x + btn_w) { if (local_x >= ob_x && local_x < ob_x + btn_w) {
if (te->pathbar_text[0]) { if (te->pathbar_text[0]) {
te_load_file(te, te->pathbar_text); te_load_file(te, te->pathbar_text);
// Update window title
char title[64]; char title[64];
snprintf(title, 64, "%s - Editor", te->filename); snprintf(title, 64, "%s - Editor", te->filename);
montauk::strncpy(win->title, title, 63); montauk::strncpy(win->title, title, 63);
@@ -537,26 +699,42 @@ static void texteditor_on_mouse(Window* win, MouseEvent& ev) {
return; return;
} }
// ---- Editor area clicks ---- // ---- 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) { if (ev.left_pressed() && local_y >= editor_y_start && local_y < editor_y_start + text_area_h
int clicked_line = te->scroll_y + (local_y - editor_y_start) / cell_h; && local_x > TE_LINE_NUM_W && local_x < cr.w - TE_SCROLLBAR_W) {
if (clicked_line >= te->line_count) clicked_line = te->line_count - 1; int pos = te_hit_test(te, local_x, local_y, editor_y_start);
if (clicked_line < 0) clicked_line = 0; te->cursor_pos = pos;
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;
te_update_cursor_pos(te); 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 ---- // ---- Scroll ----
if (ev.scroll != 0 && local_y >= editor_y_start && local_y < editor_y_start + text_area_h) { if (ev.scroll != 0 && local_y >= editor_y_start && local_y < editor_y_start + text_area_h) {
te->scroll_y -= ev.scroll * 3; te->scroll_y -= ev.scroll * 3;
if (te->scroll_y < 0) te->scroll_y = 0; 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 (max_scroll < 0) max_scroll = 0;
if (te->scroll_y > max_scroll) te->scroll_y = max_scroll; 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; return;
} }
// Arrow keys // Ctrl+A: select all
if (key.scancode == 0x48) { te_move_up(te); return; } if (key.ctrl && (key.ascii == 'a' || key.ascii == 'A')) {
if (key.scancode == 0x50) { te_move_down(te); return; } te->sel_anchor = 0;
if (key.scancode == 0x4B) { te_move_left(te); return; } te->sel_end = te->buf_len;
if (key.scancode == 0x4D) { te_move_right(te); return; } 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 // 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 // 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 // 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 // Backspace
if (key.ascii == '\b' || key.scancode == 0x0E) { if (key.ascii == '\b' || key.scancode == 0x0E) {
te_backspace(te); if (te->has_selection) te_delete_selection(te);
else te_backspace(te);
return; return;
} }
// Enter // Enter
if (key.ascii == '\n' || key.ascii == '\r') { if (key.ascii == '\n' || key.ascii == '\r') {
if (te->has_selection) te_delete_selection(te);
te_insert_char(te, '\n'); te_insert_char(te, '\n');
return; return;
} }
// Tab // Tab
if (key.ascii == '\t') { if (key.ascii == '\t') {
if (te->has_selection) te_delete_selection(te);
for (int i = 0; i < TE_TAB_WIDTH; i++) { for (int i = 0; i < TE_TAB_WIDTH; i++) {
te_insert_char(te, ' '); te_insert_char(te, ' ');
} }
@@ -670,6 +941,7 @@ static void texteditor_on_key(Window* win, const Montauk::KeyEvent& key) {
// Printable characters // Printable characters
if (key.ascii >= 32 && key.ascii < 127) { if (key.ascii >= 32 && key.ascii < 127) {
if (te->has_selection) te_delete_selection(te);
te_insert_char(te, key.ascii); te_insert_char(te, key.ascii);
return; return;
} }
@@ -706,6 +978,12 @@ void open_texteditor(DesktopState* ds) {
te->pathbar_text[0] = '\0'; te->pathbar_text[0] = '\0';
te->pathbar_cursor = 0; te->pathbar_cursor = 0;
te->pathbar_len = 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_recompute_lines(te);
te_update_cursor_pos(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) { void open_texteditor_with_file(DesktopState* ds, const char* path) {
// Extract filename for window title
const char* name = path; const char* name = path;
for (int i = 0; path[i]; i++) { for (int i = 0; path[i]; i++) {
if (path[i] == '/') name = path + i + 1; 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_text[0] = '\0';
te->pathbar_cursor = 0; te->pathbar_cursor = 0;
te->pathbar_len = 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_recompute_lines(te);
te_update_cursor_pos(te); te_update_cursor_pos(te);
+12
View File
@@ -736,6 +736,18 @@ void do_update() {
flush_ui(); st.step = STEP_ERROR; return; 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]; char copy_msg[64];
snprintf(copy_msg, sizeof(copy_msg), " %d files, %d directories updated", snprintf(copy_msg, sizeof(copy_msg), " %d files, %d directories updated",
g_files_copied, g_dirs_created); g_files_copied, g_dirs_created);
+279
View File
@@ -0,0 +1,279 @@
/*
* main.cpp
* mtkfetch - System information display
* Copyright (c) 2026 Daniel Hammer
*/
#include <montauk/syscall.h>
#include <montauk/string.h>
#include <montauk/heap.h>
#include <montauk/config.h>
// ==== 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);
}
+86
View File
@@ -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)
+238
View File
@@ -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);
}
+85
View File
@@ -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;
}
}
+486
View File
@@ -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);
}
+8
View File
@@ -0,0 +1,8 @@
[app]
name = "Paint"
binary = "paint.elf"
icon = "paint.svg"
[menu]
category = "Applications"
visible = true
+198
View File
@@ -0,0 +1,198 @@
/*
* paint.h
* Shared header for the MontaukOS Paint app
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <montauk/syscall.h>
#include <montauk/string.h>
#include <montauk/heap.h>
#include <gui/gui.hpp>
#include <gui/truetype.hpp>
#include <gui/stb_math.h>
extern "C" {
#include <string.h>
#include <stdio.h>
}
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();
+204
View File
@@ -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);
}
}
+35
View File
@@ -0,0 +1,35 @@
/*
* stb_truetype_impl.cpp
* Single compilation unit for stb_truetype in MontaukOS freestanding environment
* Copyright (c) 2026 Daniel Hammer
*/
#include <cstdint>
#include <cstddef>
#include <montauk/heap.h>
#include <montauk/string.h>
#include <gui/stb_math.h>
// 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 <gui/stb_truetype.h>
+62 -28
View File
@@ -6,19 +6,36 @@
#include "shell.h" #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); int h = montauk::open(path);
if (h < 0) return false; if (h < 0) return false;
montauk::close(h); 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); int pid = montauk::spawn(path, args);
if (pid < 0) return false; if (pid < 0) return false;
montauk::waitpid(pid); montauk::waitpid(pid);
return true; 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 ---- // ---- Resolve arguments: expand relative file paths against CWD ----
static void resolve_args(const char* args, char* out, int outMax) { 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; int j = 0;
while (cwd[j] && r < 255) candidate[r++] = cwd[j++]; while (cwd[j] && r < 255) candidate[r++] = cwd[j++];
if (cwd[0] && r < 255) candidate[r++] = '/'; 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'; candidate[r] = '\0';
int h = montauk::open(candidate); int h = montauk::open(candidate);
@@ -82,38 +104,50 @@ int exec_external(const char* cmd, const char* args) {
resolve_args(args, resolvedArgs, sizeof(resolvedArgs)); resolve_args(args, resolvedArgs, sizeof(resolvedArgs));
const char* finalArgs = resolvedArgs[0] ? resolvedArgs : nullptr; const char* finalArgs = resolvedArgs[0] ? resolvedArgs : nullptr;
// 1. Try 0:/os/<cmd>.elf // Strip leading "./" from command name
scopy(path, "0:/os/", sizeof(path)); const char* name = cmd;
scat(path, cmd, sizeof(path)); if (name[0] == '.' && name[1] == '/') name += 2;
scat(path, ".elf", sizeof(path));
if (try_exec(path, finalArgs)) return 0;
// 2. Try 0:/games/<cmd>.elf // 0. If cmd has a drive prefix (absolute path), try it directly
scopy(path, "0:/games/", sizeof(path)); if (has_drive_prefix(cmd)) {
scat(path, cmd, sizeof(path)); if (try_exec(cmd, finalArgs)) return 0;
scat(path, ".elf", sizeof(path)); montauk::print(cmd);
if (try_exec(path, finalArgs)) return 0; montauk::print(": not found\n");
return 127;
// 3. Try N:/<cwd>/<cmd>.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;
} }
// 4. Try N:/<cmd>.elf on current drive // 1. Try as-is in CWD (exact name, e.g., "a.out" or "hello.elf")
build_drive_path(current_drive, "", path, sizeof(path)); build_cwd_path(name, path, sizeof(path));
scat(path, cmd, 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)); scat(path, ".elf", sizeof(path));
if (try_exec(path, finalArgs)) return 0; if (try_exec(path, finalArgs)) return 0;
// 5. If on a non-zero drive, also try 0:/<cmd>.elf // 3. Try 0:/os/<cmd>.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/<cmd> (no extension)
scopy(path, "0:/os/", sizeof(path));
scat(path, name, sizeof(path));
if (try_exec(path, finalArgs)) return 0;
// 5. Try 0:/games/<cmd>.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) { if (current_drive != 0) {
scopy(path, "0:/", sizeof(path)); build_drive_path(current_drive, name, path, sizeof(path));
scat(path, cmd, sizeof(path)); if (try_exec(path, finalArgs)) return 0;
build_drive_path(current_drive, name, path, sizeof(path));
scat(path, ".elf", sizeof(path)); scat(path, ".elf", sizeof(path));
if (try_exec(path, finalArgs)) return 0; if (try_exec(path, finalArgs)) return 0;
} }
+56
View File
@@ -213,6 +213,62 @@ void apply_format(NumFormat f) {
// Scroll clamping // 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() { void clamp_scroll() {
int pbh = g_pathbar_open ? PATHBAR_H : 0; int pbh = g_pathbar_open ? PATHBAR_H : 0;
int max_x = content_width() - (g_win_w - ROW_HEADER_W); int max_x = content_width() - (g_win_w - ROW_HEADER_W);
+239
View File
@@ -6,6 +6,34 @@
#include "spreadsheet.h" #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 // Cell reference parsing
// ============================================================================ // ============================================================================
@@ -124,6 +152,7 @@ static double eval_primary(const char* s, int* pos, bool* ok) {
} }
fname[fi] = '\0'; fname[fi] = '\0';
// Range functions: SUM, AVG, MIN, MAX, COUNT
if (s[*pos] == '(' && (strcmp(fname, "SUM") == 0 || if (s[*pos] == '(' && (strcmp(fname, "SUM") == 0 ||
strcmp(fname, "AVG") == 0 || strcmp(fname, "AVG") == 0 ||
strcmp(fname, "MIN") == 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); 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; *pos = save_pos;
int col, row, consumed; int col, row, consumed;
if (parse_cell_ref(s + *pos, &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 if (r >= 10) { buf[1] = '0' + r / 10; buf[2] = '0' + r % 10; buf[3] = '\0'; }
else { buf[1] = '0' + r; buf[2] = '\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';
}
+206 -10
View File
@@ -60,6 +60,25 @@ UndoEntry* g_undo[UNDO_MAX + 1];
int g_undo_count = 0; int g_undo_count = 0;
int g_undo_pos = 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 // Hit testing
// ============================================================================ // ============================================================================
@@ -89,6 +108,28 @@ bool hit_cell(int mx, int my, int* out_col, int* out_row) {
return true; 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) { 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; 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] = {}; char args[512] = {};
int arglen = montauk::getargs(args, sizeof(args)); int arglen = montauk::getargs(args, sizeof(args));
if (arglen > 0 && args[0]) { if (arglen > 0 && args[0]) {
str_cpy(g_filepath, args, 256); load_file(args);
load_file(g_filepath);
} }
// Build window title // Build window title
@@ -295,21 +335,56 @@ extern "C" void _start() {
goto done_keys; 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 // Escape: cancel edit or quit
if (key.scancode == 0x01) { if (key.scancode == 0x01) {
if (g_editing) { cancel_edit(); redraw = true; } if (g_editing) { cancel_edit(); g_ac_open = false; redraw = true; }
else break; else break;
} }
// Enter: commit edit and move down // Enter: commit edit and move down
else if (key.ascii == '\n' || key.ascii == '\r') { 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++; if (g_sel_row < MAX_ROWS - 1) g_sel_row++;
ensure_sel_visible(); ensure_sel_visible();
redraw = true; redraw = true;
} }
// Tab: commit and move right // Tab: commit and move right (or accept autocomplete above)
else if (key.ascii == '\t') { else if (key.ascii == '\t') {
if (g_editing) commit_edit(); if (g_editing) { commit_edit(); g_ac_open = false; }
if (key.shift) { if (key.shift) {
if (g_sel_col > 0) g_sel_col--; if (g_sel_col > 0) g_sel_col--;
} else { } else {
@@ -372,6 +447,7 @@ extern "C" void _start() {
g_edit_len--; g_edit_len--;
g_edit_cursor--; g_edit_cursor--;
g_edit_buf[g_edit_len] = '\0'; g_edit_buf[g_edit_len] = '\0';
update_autocomplete();
} }
redraw = true; redraw = true;
} else { } else {
@@ -394,6 +470,7 @@ extern "C" void _start() {
g_edit_buf[i] = g_edit_buf[i + 1]; g_edit_buf[i] = g_edit_buf[i + 1];
g_edit_len--; g_edit_len--;
g_edit_buf[g_edit_len] = '\0'; g_edit_buf[g_edit_len] = '\0';
update_autocomplete();
} }
redraw = true; redraw = true;
} else { } else {
@@ -411,10 +488,40 @@ extern "C" void _start() {
// Edit mode arrow keys (cursor movement within formula bar) // Edit mode arrow keys (cursor movement within formula bar)
else if (key.scancode == 0x4B && g_editing) { else if (key.scancode == 0x4B && g_editing) {
if (g_edit_cursor > 0) g_edit_cursor--; if (g_edit_cursor > 0) g_edit_cursor--;
update_autocomplete();
redraw = true; redraw = true;
} }
else if (key.scancode == 0x4D && g_editing) { else if (key.scancode == 0x4D && g_editing) {
if (g_edit_cursor < g_edit_len) g_edit_cursor++; 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; redraw = true;
} }
// Ctrl+B: bold toggle // Ctrl+B: bold toggle
@@ -487,6 +594,7 @@ extern "C" void _start() {
g_edit_cursor++; g_edit_cursor++;
g_edit_buf[g_edit_len] = '\0'; g_edit_buf[g_edit_len] = '\0';
} }
update_autocomplete();
redraw = true; redraw = true;
} }
// F2: edit current cell content (append mode) // F2: edit current cell content (append mode)
@@ -510,11 +618,15 @@ extern "C" void _start() {
int pbh = g_pathbar_open ? PATHBAR_H : 0; int pbh = g_pathbar_open ? PATHBAR_H : 0;
int header_y = TOOLBAR_H + pbh + FORMULA_BAR_H; 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 int cursor = 0; // arrow
if (g_col_resizing) { if (g_col_resizing) {
cursor = 1; // resize_h while dragging 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) { } else if (my >= header_y && my < header_y + COL_HEADER_H) {
for (int c = 0; c < MAX_COLS; c++) { for (int c = 0; c < MAX_COLS; c++) {
int cx = col_x(c) - g_scroll_x + g_col_widths[c] - 1; 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); 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 // Column resize: drag in progress
if (g_col_resizing) { if (g_col_resizing) {
if (left_held) { if (left_held) {
@@ -543,11 +682,39 @@ extern "C" void _start() {
goto done_mouse; 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) { if (clicked && my >= header_y && my < header_y + COL_HEADER_H) {
for (int c = 0; c < MAX_COLS; c++) { for (int c = 0; c < MAX_COLS; c++) {
int cx = col_x(c) - g_scroll_x + g_col_widths[c] - 1; int cx = col_x(c) - g_scroll_x + g_col_widths[c] - 1;
if (mx >= cx - COL_RESIZE_GRAB && mx <= cx + COL_RESIZE_GRAB) { 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_resizing = true;
g_col_resize_idx = c; g_col_resize_idx = c;
g_col_resize_start_x = mx; g_col_resize_start_x = mx;
@@ -565,12 +732,41 @@ extern "C" void _start() {
redraw = true; redraw = true;
} }
else { 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; int col, row;
if (hit_cell(mx, my, &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_col = col;
g_sel_row = row; 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; g_fmt_dropdown_open = false;
redraw = true; redraw = true;
} }
+92 -9
View File
@@ -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); 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; int c0, r0, c1, r1;
sel_range(&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]; for (int c = c0; c <= c1; c++) sw += g_col_widths[c];
int sh = (r1 - r0 + 1) * ROW_H; 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, 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); 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 ---- // ---- Status bar ----
@@ -302,15 +321,35 @@ void render(uint32_t* pixels) {
int sty = sy + (STATUS_BAR_H - HEADER_FONT) / 2; 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); 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) { if (g_has_selection) {
int c0, r0, c1, r1; int c0, r0, c1, r1;
sel_range(&c0, &r0, &c1, &r1); sel_range(&c0, &r0, &c1, &r1);
char n0[8], n1[8];
cell_name(n0, c0, r0); // Calculate aggregates for numeric cells
cell_name(n1, c1, r1); double sum = 0;
int ncells = (c1 - c0 + 1) * (r1 - r0 + 1); int num_count = 0;
snprintf(right, 64, "%s:%s (%d cells) ", n0, n1, ncells); 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 { } else {
Cell* sel = &g_cells[g_sel_row][g_sel_col]; Cell* sel = &g_cells[g_sel_row][g_sel_col];
char cname[8]; char cname[8];
@@ -318,9 +357,9 @@ void render(uint32_t* pixels) {
if (sel->type == CT_FORMULA || sel->type == CT_NUMBER) { if (sel->type == CT_FORMULA || sel->type == CT_NUMBER) {
char vbuf[32]; char vbuf[32];
double_to_str(vbuf, 32, sel->value); double_to_str(vbuf, 32, sel->value);
snprintf(right, 64, "%s = %s ", cname, vbuf); snprintf(right, 128, "%s = %s ", cname, vbuf);
} else { } else {
snprintf(right, 64, "%s ", cname); snprintf(right, 128, "%s ", cname);
} }
} }
int rw = g_font->measure_text(right, HEADER_FONT); 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); 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);
}
}
} }
+29
View File
@@ -11,6 +11,7 @@
#include <montauk/heap.h> #include <montauk/heap.h>
#include <gui/gui.hpp> #include <gui/gui.hpp>
#include <gui/truetype.hpp> #include <gui/truetype.hpp>
#include <gui/stb_math.h>
extern "C" { extern "C" {
#include <string.h> #include <string.h>
@@ -41,6 +42,9 @@ static constexpr int DEF_COL_W = 100;
static constexpr int MIN_COL_W = 30; static constexpr int MIN_COL_W = 30;
static constexpr int ROW_H = 26; static constexpr int ROW_H = 26;
static constexpr int COL_RESIZE_GRAB = 5; // pixels from border edge for grab zone 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 CELL_TEXT_MAX = 128;
static constexpr int FONT_SIZE = 18; 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_count;
extern int g_undo_pos; 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 // Function declarations — helpers.cpp
// ============================================================================ // ============================================================================
@@ -203,6 +226,9 @@ int content_width();
int content_height(); int content_height();
void cell_name(char* buf, int col, int row); void cell_name(char* buf, int col, int row);
void format_value(char* buf, int max, double val, NumFormat fmt); 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 // Function declarations — fileio.cpp
@@ -231,6 +257,8 @@ void apply_align(CellAlign a);
void apply_format(NumFormat f); void apply_format(NumFormat f);
void clamp_scroll(); void clamp_scroll();
void ensure_sel_visible(); 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 // 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_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_toolbar_click(int mx, int my);
bool handle_fmt_dropdown_click(int mx, int my); bool handle_fmt_dropdown_click(int mx, int my);
+504
View File
@@ -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.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
+153
View File
@@ -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)
+1
View File
@@ -0,0 +1 @@
0.9.28rc
+446
View File
@@ -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 "!<arch>\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)|(DT_PTR<<N_BTSHFT_COFF)|(x&N_BTMASK_COFF))
#define DECREF_COFF(x) ((((x)>>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"
+42
View File
@@ -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 */
+77
View File
@@ -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();
}
+7
View File
@@ -0,0 +1,7 @@
/*
* crti.c
* Init section prologue (minimal for MontaukOS)
* Copyright (c) 2026 Daniel Hammer
*/
/* Empty -- MontaukOS userspace has no global constructors */
+7
View File
@@ -0,0 +1,7 @@
/*
* crtn.c
* Init section epilogue (minimal for MontaukOS)
* Copyright (c) 2026 Daniel Hammer
*/
/* Empty -- MontaukOS userspace has no global destructors */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+490
View File
@@ -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
+332
View File
@@ -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
File diff suppressed because it is too large Load Diff
+128
View File
@@ -0,0 +1,128 @@
#ifndef LIBTCC_H
#define LIBTCC_H
#ifndef LIBTCCAPI
# define LIBTCCAPI
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*****************************/
/* set custom allocator for all allocations (optional), NULL for default. */
typedef void *TCCReallocFunc(void *ptr, unsigned long size);
LIBTCCAPI void tcc_set_realloc(TCCReallocFunc *my_realloc);
/*****************************/
typedef struct TCCState TCCState;
/* create a new TCC compilation context */
LIBTCCAPI TCCState *tcc_new(void);
/* free a TCC compilation context */
LIBTCCAPI void tcc_delete(TCCState *s);
/* set CONFIG_TCCDIR at runtime */
LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path);
/* set error/warning callback (optional) */
typedef void TCCErrorFunc(void *opaque, const char *msg);
LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, TCCErrorFunc *error_func);
/* set options as from command line (multiple supported) */
LIBTCCAPI int tcc_set_options(TCCState *s, const char *str);
/*****************************/
/* preprocessor */
/* add include path */
LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname);
/* add in system include path */
LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname);
/* define preprocessor symbol 'sym'. value can be NULL, sym can be "sym=val" */
LIBTCCAPI void tcc_define_symbol(TCCState *s, const char *sym, const char *value);
/* undefine preprocess symbol 'sym' */
LIBTCCAPI void tcc_undefine_symbol(TCCState *s, const char *sym);
/*****************************/
/* compiling */
/* add a file (C file, dll, object, library, ld script). Return -1 if error. */
LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename);
/* compile a string containing a C source. Return -1 if error. */
LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf);
/* Tip: to have more specific errors/warnings from tcc_compile_string(),
you can prefix the string with "#line <num> \"<filename>\"\n" */
/*****************************/
/* linking commands */
/* set output type. MUST BE CALLED before any compilation */
LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type);
#define TCC_OUTPUT_MEMORY 1 /* output will be run in memory */
#define TCC_OUTPUT_EXE 2 /* executable file */
#define TCC_OUTPUT_DLL 4 /* dynamic library */
#define TCC_OUTPUT_OBJ 3 /* object file */
#define TCC_OUTPUT_PREPROCESS 5 /* only preprocess */
/* equivalent to -Lpath option */
LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname);
/* the library name is the same as the argument of the '-l' option */
LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname);
/* add a symbol to the compiled program */
LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val);
/* output an executable, library or object file. DO NOT call
tcc_relocate() before. */
LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename);
/* link and run main() function and return its value. DO NOT call
tcc_relocate() before. */
LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv);
/* do all relocations (needed before using tcc_get_symbol()) */
LIBTCCAPI int tcc_relocate(TCCState *s1);
/* return symbol value or NULL if not found */
LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name);
/* list all (global) symbols and their values via 'symbol_cb()' */
LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx,
void (*symbol_cb)(void *ctx, const char *name, const void *val));
/* experimental/advanced section (see libtcc_test_mt.c for an example) */
/* catch runtime exceptions (optionally limit backtraces at top_func),
when using tcc_set_options("-bt") and when not using tcc_run() */
LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *jmp_buf, void *top_func, void *longjmp);
#define tcc_setjmp(s1,jb,f) setjmp(_tcc_setjmp(s1, jb, f, longjmp))
/* debugging */
/* For debugging to work you have to enable it with tcc_set_options */
/* compile a string containing a C source. Return -1 if error.
Write the string to file filename if debug is set. */
LIBTCCAPI int tcc_compile_string_file(TCCState *s, const char *buf, const char *filename);
/* Output object file. This must be done after tcc_relocate.
It only generates the file if debug is set.
The filename can be loaded with gdb command add-symbol-file */
LIBTCCAPI int elf_output_obj(TCCState *s1, const char *filename);
/* custom error printer for runtime exceptions. Returning 0 stops backtrace */
typedef int TCCBtFunc(void *udata, void *pc, const char *file, int line, const char* func, const char *msg);
LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, void* userdata, TCCBtFunc*);
#ifdef __cplusplus
}
#endif
#endif
+221
View File
@@ -0,0 +1,221 @@
/*
* montauk_compat.h
* POSIX compatibility shims for TCC on MontaukOS
* Copyright (c) 2026 Daniel Hammer
*/
#ifndef MONTAUK_COMPAT_H
#define MONTAUK_COMPAT_H
#include <stddef.h>
#include <stdint.h>
/* ====================================================================
setjmp / longjmp (implemented in setjmp.S)
==================================================================== */
typedef unsigned long jmp_buf[8]; /* rbx, rbp, r12-r15, rsp, rip */
int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int val) __attribute__((noreturn));
/* ====================================================================
time stubs (for __DATE__ / __TIME__ macros)
==================================================================== */
typedef long time_t;
struct tm {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
static inline time_t time(time_t *t) {
if (t) *t = 0;
return 0;
}
static inline struct tm *localtime(const time_t *t) {
static struct tm tm0 = {
.tm_sec = 0, .tm_min = 0, .tm_hour = 12,
.tm_mday = 1, .tm_mon = 0, .tm_year = 126, /* 2026 */
.tm_wday = 4, .tm_yday = 0, .tm_isdst = 0
};
(void)t;
return &tm0;
}
/* ====================================================================
gettimeofday stub (for timing in tcc.c)
==================================================================== */
struct timeval {
long tv_sec;
long tv_usec;
};
struct timezone {
int tz_minuteswest;
int tz_dsttime;
};
static inline int gettimeofday(struct timeval *tv, struct timezone *tz) {
if (tv) { tv->tv_sec = 0; tv->tv_usec = 0; }
(void)tz;
return 0;
}
/* ====================================================================
getcwd stub (for debug info)
==================================================================== */
static inline char *getcwd(char *buf, size_t size) {
if (buf && size > 4) {
buf[0] = '0';
buf[1] = ':';
buf[2] = '/';
buf[3] = '\0';
}
return buf;
}
/* ====================================================================
POSIX file access stubs
==================================================================== */
#define R_OK 4
#define W_OK 2
#define X_OK 1
#define F_OK 0
/* Check if file exists by trying to open it */
int access(const char *path, int mode);
/* chmod - no-op on MontaukOS */
static inline int chmod(const char *path, unsigned int mode) {
(void)path; (void)mode;
return 0;
}
/* close (provided by libc) */
int close(int fd);
/* lseek - provided by libc, tracks fd positions */
long lseek(int fd, long offset, int whence);
/* realpath - just return a copy of the path */
static inline char *realpath(const char *path, char *resolved) {
if (path == NULL) return NULL;
if (resolved == NULL) {
size_t len = 0;
const char *p = path;
while (*p++) len++;
resolved = (char*)malloc(len + 1);
if (!resolved) return NULL;
}
{
const char *s = path;
char *d = resolved;
while ((*d++ = *s++));
}
return resolved;
}
/* ====================================================================
strtof / strtold stubs
==================================================================== */
/* These are declared extern in tcc.h for non-Win32.
We provide no-op stubs since the libc has no FP parse. */
static inline float strtof(const char *nptr, char **endptr) {
(void)nptr;
if (endptr) *endptr = (char*)nptr;
return 0.0f;
}
static inline long double strtold(const char *nptr, char **endptr) {
(void)nptr;
if (endptr) *endptr = (char*)nptr;
return 0.0L;
}
/* dlfcn stubs not needed -- TCC_IS_NATIVE is disabled for MontaukOS */
/* ====================================================================
ssize_t (used in tccelf.c)
==================================================================== */
#ifndef _SSIZE_T_DEFINED
#define _SSIZE_T_DEFINED
typedef long ssize_t;
#endif
/* ====================================================================
POSIX I/O (provided by libc)
==================================================================== */
int read(int fd, void *buf, size_t count);
int write(int fd, const void *buf, size_t count);
/* unlink = remove */
static inline int unlink(const char *path) {
return remove(path);
}
/* fputc (should be in libc but isn't yet) */
static inline int fputc(int c, FILE *stream) {
unsigned char ch = (unsigned char)c;
size_t n = fwrite(&ch, 1, 1, stream);
return n == 1 ? c : -1;
}
/* fdopen - MontaukOS doesn't have fd-to-FILE conversion.
TCC uses fdopen after creating a file with open().
We return NULL and let TCC fall back to error path,
or we can use a workaround. */
FILE *fdopen(int fd, const char *mode);
/* strerror */
static inline const char *strerror(int errnum) {
(void)errnum;
return "error";
}
/* ====================================================================
String functions missing from MontaukOS libc
==================================================================== */
static inline char *strpbrk(const char *s, const char *accept) {
for (; *s; s++) {
for (const char *a = accept; *a; a++) {
if (*s == *a) return (char *)s;
}
}
return NULL;
}
/* ====================================================================
Process stubs
==================================================================== */
static inline int execvp(const char *file, char *const argv[]) {
(void)file; (void)argv;
return -1;
}
/* ====================================================================
Floating-point parsing and math
==================================================================== */
double strtod(const char *nptr, char **endptr);
double ldexp(double x, int n);
long double ldexpl(long double x, int n);
#endif /* MONTAUK_COMPAT_H */
+229
View File
@@ -0,0 +1,229 @@
/*
* montauk_main.c
* MontaukOS entry point and POSIX compat functions for TCC
* Copyright (c) 2026 Daniel Hammer
*/
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* ====================================================================
Raw syscall wrappers
==================================================================== */
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_OPEN 6
#define SYS_GETSIZE 8
#define SYS_CLOSE 9
#define SYS_GETARGS 25
/* ====================================================================
access() - check if a file exists
==================================================================== */
int access(const char *path, int mode) {
(void)mode;
if (path == NULL) return -1;
int h = (int)_sys1(SYS_OPEN, (long)path);
if (h < 0) return -1;
_sys1(SYS_CLOSE, (long)h);
return 0;
}
/* ====================================================================
fdopen - wrap a raw fd in a FILE (needed by tccelf.c)
==================================================================== */
FILE *fdopen(int fd, const char *mode) {
(void)mode;
if (fd < 0) return NULL;
unsigned long fileSize = (unsigned long)_sys1(SYS_GETSIZE, (long)fd);
FILE *f = (FILE *)malloc(sizeof(FILE));
if (f == NULL) return NULL;
f->handle = fd;
f->pos = 0;
f->size = fileSize;
f->eof = 0;
f->error = 0;
f->is_std = 0;
f->ungetc_buf = -1;
return f;
}
/* ====================================================================
Floating point support (needed by TCC for parsing float literals)
==================================================================== */
double ldexp(double x, int n) {
/* Use bit manipulation via union for exact results */
if (x == 0.0 || n == 0) return x;
while (n > 0) { x *= 2.0; n--; }
while (n < 0) { x *= 0.5; n++; }
return x;
}
long double ldexpl(long double x, int n) {
return (long double)ldexp((double)x, n);
}
double strtod(const char *nptr, char **endptr) {
double result = 0.0;
double sign = 1.0;
const char *s = nptr;
while (*s == ' ' || *s == '\t' || *s == '\n') s++;
if (*s == '-') { sign = -1.0; s++; }
else if (*s == '+') s++;
/* Integer part */
while (*s >= '0' && *s <= '9')
result = result * 10.0 + (*s++ - '0');
/* Fractional part */
if (*s == '.') {
s++;
double frac = 0.1;
while (*s >= '0' && *s <= '9') {
result += (*s++ - '0') * frac;
frac *= 0.1;
}
}
/* Exponent */
if (*s == 'e' || *s == 'E') {
s++;
int exp_sign = 1, exp_val = 0;
if (*s == '-') { exp_sign = -1; s++; }
else if (*s == '+') s++;
while (*s >= '0' && *s <= '9')
exp_val = exp_val * 10 + (*s++ - '0');
double exp_mult = 1.0;
for (int i = 0; i < exp_val; i++)
exp_mult *= 10.0;
if (exp_sign > 0) result *= exp_mult;
else result /= exp_mult;
}
/* Hex float (0x...p...) */
if (nptr[0] == '0' && (nptr[1] == 'x' || nptr[1] == 'X')) {
s = nptr + 2;
result = 0.0;
while (1) {
int d;
if (*s >= '0' && *s <= '9') d = *s - '0';
else if (*s >= 'a' && *s <= 'f') d = *s - 'a' + 10;
else if (*s >= 'A' && *s <= 'F') d = *s - 'A' + 10;
else break;
result = result * 16.0 + d;
s++;
}
if (*s == '.') {
s++;
double frac = 1.0 / 16.0;
while (1) {
int d;
if (*s >= '0' && *s <= '9') d = *s - '0';
else if (*s >= 'a' && *s <= 'f') d = *s - 'a' + 10;
else if (*s >= 'A' && *s <= 'F') d = *s - 'A' + 10;
else break;
result += d * frac;
frac /= 16.0;
s++;
}
}
if (*s == 'p' || *s == 'P') {
s++;
int exp_sign = 1, exp_val = 0;
if (*s == '-') { exp_sign = -1; s++; }
else if (*s == '+') s++;
while (*s >= '0' && *s <= '9')
exp_val = exp_val * 10 + (*s++ - '0');
result = ldexp(result, exp_sign * exp_val);
}
}
if (endptr) *endptr = (char *)s;
return sign * result;
}
/* ====================================================================
strtoll / strtoull (needed by TCC, not in MontaukOS libc)
==================================================================== */
long long strtoll(const char *nptr, char **endptr, int base) {
return (long long)strtol(nptr, endptr, base);
}
unsigned long long strtoull(const char *nptr, char **endptr, int base) {
return (unsigned long long)strtoul(nptr, endptr, base);
}
/* ====================================================================
_start entry point
==================================================================== */
int main(int argc, char **argv);
void _start(void) {
/* Get command-line arguments from kernel */
char argbuf[256];
int len = (int)_sys2(SYS_GETARGS, (long)argbuf, sizeof(argbuf));
/* Parse into argv[] -- split on spaces, simple tokenizer */
char *argv[32];
int argc = 0;
/* argv[0] = program name */
argv[argc++] = "tcc";
if (len > 0) {
argbuf[len < 255 ? len : 255] = '\0';
char *p = argbuf;
while (*p && argc < 31) {
while (*p == ' ') p++;
if (*p == '\0') break;
if (*p == '"') {
p++;
argv[argc++] = p;
while (*p && *p != '"') p++;
} else {
argv[argc++] = p;
while (*p && *p != ' ') p++;
}
if (*p) *p++ = '\0';
}
}
argv[argc] = NULL;
int ret = main(argc, argv);
exit(ret);
}
+56
View File
@@ -0,0 +1,56 @@
/*
* setjmp.S
* setjmp/longjmp for x86_64 MontaukOS
* Copyright (c) 2026 Daniel Hammer
*
* jmp_buf layout (8 x uint64_t):
* [0] = rbx
* [1] = rbp
* [2] = r12
* [3] = r13
* [4] = r14
* [5] = r15
* [6] = rsp (after return from setjmp)
* [7] = rip (return address)
*/
.text
.global setjmp
.type setjmp, @function
setjmp:
/* rdi = jmp_buf */
mov %rbx, (%rdi)
mov %rbp, 8(%rdi)
mov %r12, 16(%rdi)
mov %r13, 24(%rdi)
mov %r14, 32(%rdi)
mov %r15, 40(%rdi)
/* rsp as it will be after we return (pop return address) */
lea 8(%rsp), %rax
mov %rax, 48(%rdi)
/* return address */
mov (%rsp), %rax
mov %rax, 56(%rdi)
/* return 0 */
xor %eax, %eax
ret
.global longjmp
.type longjmp, @function
longjmp:
/* rdi = jmp_buf, esi = val */
mov %esi, %eax
/* longjmp(buf, 0) must return 1 */
test %eax, %eax
jnz 1f
inc %eax
1:
mov (%rdi), %rbx
mov 8(%rdi), %rbp
mov 16(%rdi), %r12
mov 24(%rdi), %r13
mov 32(%rdi), %r14
mov 40(%rdi), %r15
mov 48(%rdi), %rsp
jmp *56(%rdi)
+234
View File
@@ -0,0 +1,234 @@
/* Table of DBX symbol codes for the GNU system.
Copyright (C) 1988, 1997 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 Library General Public License as
published by the Free Software Foundation; either version 2 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* This contains contribution from Cygnus Support. */
/* Global variable. Only the name is significant.
To find the address, look in the corresponding external symbol. */
__define_stab (N_GSYM, 0x20, "GSYM")
/* Function name for BSD Fortran. Only the name is significant.
To find the address, look in the corresponding external symbol. */
__define_stab (N_FNAME, 0x22, "FNAME")
/* Function name or text-segment variable for C. Value is its address.
Desc is supposedly starting line number, but GCC doesn't set it
and DBX seems not to miss it. */
__define_stab (N_FUN, 0x24, "FUN")
/* Data-segment variable with internal linkage. Value is its address.
"Static Sym". */
__define_stab (N_STSYM, 0x26, "STSYM")
/* BSS-segment variable with internal linkage. Value is its address. */
__define_stab (N_LCSYM, 0x28, "LCSYM")
/* Name of main routine. Only the name is significant.
This is not used in C. */
__define_stab (N_MAIN, 0x2a, "MAIN")
/* Global symbol in Pascal.
Supposedly the value is its line number; I'm skeptical. */
__define_stab (N_PC, 0x30, "PC")
/* Number of symbols: 0, files,,funcs,lines according to Ultrix V4.0. */
__define_stab (N_NSYMS, 0x32, "NSYMS")
/* "No DST map for sym: name, ,0,type,ignored" according to Ultrix V4.0. */
__define_stab (N_NOMAP, 0x34, "NOMAP")
/* New stab from Solaris. I don't know what it means, but it
don't seem to contain useful information. */
__define_stab (N_OBJ, 0x38, "OBJ")
/* New stab from Solaris. I don't know what it means, but it
don't seem to contain useful information. Possibly related to the
optimization flags used in this module. */
__define_stab (N_OPT, 0x3c, "OPT")
/* Register variable. Value is number of register. */
__define_stab (N_RSYM, 0x40, "RSYM")
/* Modula-2 compilation unit. Can someone say what info it contains? */
__define_stab (N_M2C, 0x42, "M2C")
/* Line number in text segment. Desc is the line number;
value is corresponding address. */
__define_stab (N_SLINE, 0x44, "SLINE")
/* Similar, for data segment. */
__define_stab (N_DSLINE, 0x46, "DSLINE")
/* Similar, for bss segment. */
__define_stab (N_BSLINE, 0x48, "BSLINE")
/* Sun's source-code browser stabs. ?? Don't know what the fields are.
Supposedly the field is "path to associated .cb file". THIS VALUE
OVERLAPS WITH N_BSLINE! */
__define_stab (N_BROWS, 0x48, "BROWS")
/* GNU Modula-2 definition module dependency. Value is the modification time
of the definition file. Other is non-zero if it is imported with the
GNU M2 keyword %INITIALIZE. Perhaps N_M2C can be used if there
are enough empty fields? */
__define_stab(N_DEFD, 0x4a, "DEFD")
/* THE FOLLOWING TWO STAB VALUES CONFLICT. Happily, one is for Modula-2
and one is for C++. Still,... */
/* GNU C++ exception variable. Name is variable name. */
__define_stab (N_EHDECL, 0x50, "EHDECL")
/* Modula2 info "for imc": name,,0,0,0 according to Ultrix V4.0. */
__define_stab (N_MOD2, 0x50, "MOD2")
/* GNU C++ `catch' clause. Value is its address. Desc is nonzero if
this entry is immediately followed by a CAUGHT stab saying what exception
was caught. Multiple CAUGHT stabs means that multiple exceptions
can be caught here. If Desc is 0, it means all exceptions are caught
here. */
__define_stab (N_CATCH, 0x54, "CATCH")
/* Structure or union element. Value is offset in the structure. */
__define_stab (N_SSYM, 0x60, "SSYM")
/* Name of main source file.
Value is starting text address of the compilation. */
__define_stab (N_SO, 0x64, "SO")
/* Automatic variable in the stack. Value is offset from frame pointer.
Also used for type descriptions. */
__define_stab (N_LSYM, 0x80, "LSYM")
/* Beginning of an include file. Only Sun uses this.
In an object file, only the name is significant.
The Sun linker puts data into some of the other fields. */
__define_stab (N_BINCL, 0x82, "BINCL")
/* Name of sub-source file (#include file).
Value is starting text address of the compilation. */
__define_stab (N_SOL, 0x84, "SOL")
/* Parameter variable. Value is offset from argument pointer.
(On most machines the argument pointer is the same as the frame pointer. */
__define_stab (N_PSYM, 0xa0, "PSYM")
/* End of an include file. No name.
This and N_BINCL act as brackets around the file's output.
In an object file, there is no significant data in this entry.
The Sun linker puts data into some of the fields. */
__define_stab (N_EINCL, 0xa2, "EINCL")
/* Alternate entry point. Value is its address. */
__define_stab (N_ENTRY, 0xa4, "ENTRY")
/* Beginning of lexical block.
The desc is the nesting level in lexical blocks.
The value is the address of the start of the text for the block.
The variables declared inside the block *precede* the N_LBRAC symbol. */
__define_stab (N_LBRAC, 0xc0, "LBRAC")
/* Place holder for deleted include file. Replaces a N_BINCL and everything
up to the corresponding N_EINCL. The Sun linker generates these when
it finds multiple identical copies of the symbols from an include file.
This appears only in output from the Sun linker. */
__define_stab (N_EXCL, 0xc2, "EXCL")
/* Modula-2 scope information. Can someone say what info it contains? */
__define_stab (N_SCOPE, 0xc4, "SCOPE")
/* End of a lexical block. Desc matches the N_LBRAC's desc.
The value is the address of the end of the text for the block. */
__define_stab (N_RBRAC, 0xe0, "RBRAC")
/* Begin named common block. Only the name is significant. */
__define_stab (N_BCOMM, 0xe2, "BCOMM")
/* End named common block. Only the name is significant
(and it should match the N_BCOMM). */
__define_stab (N_ECOMM, 0xe4, "ECOMM")
/* End common (local name): value is address.
I'm not sure how this is used. */
__define_stab (N_ECOML, 0xe8, "ECOML")
/* These STAB's are used on Gould systems for Non-Base register symbols
or something like that. FIXME. I have assigned the values at random
since I don't have a Gould here. Fixups from Gould folk welcome... */
__define_stab (N_NBTEXT, 0xF0, "NBTEXT")
__define_stab (N_NBDATA, 0xF2, "NBDATA")
__define_stab (N_NBBSS, 0xF4, "NBBSS")
__define_stab (N_NBSTS, 0xF6, "NBSTS")
__define_stab (N_NBLCS, 0xF8, "NBLCS")
/* Second symbol entry containing a length-value for the preceding entry.
The value is the length. */
__define_stab (N_LENG, 0xfe, "LENG")
/* The above information, in matrix format.
STAB MATRIX
_________________________________________________
| 00 - 1F are not dbx stab symbols |
| In most cases, the low bit is the EXTernal bit|
| 00 UNDEF | 02 ABS | 04 TEXT | 06 DATA |
| 01 |EXT | 03 |EXT | 05 |EXT | 07 |EXT |
| 08 BSS | 0A INDR | 0C FN_SEQ | 0E |
| 09 |EXT | 0B | 0D | 0F |
| 10 | 12 COMM | 14 SETA | 16 SETT |
| 11 | 13 | 15 | 17 |
| 18 SETD | 1A SETB | 1C SETV | 1E WARNING|
| 19 | 1B | 1D | 1F FN |
|_______________________________________________|
| Debug entries with bit 01 set are unused. |
| 20 GSYM | 22 FNAME | 24 FUN | 26 STSYM |
| 28 LCSYM | 2A MAIN | 2C | 2E |
| 30 PC | 32 NSYMS | 34 NOMAP | 36 |
| 38 OBJ | 3A | 3C OPT | 3E |
| 40 RSYM | 42 M2C | 44 SLINE | 46 DSLINE |
| 48 BSLINE*| 4A DEFD | 4C | 4E |
| 50 EHDECL*| 52 | 54 CATCH | 56 |
| 58 | 5A | 5C | 5E |
| 60 SSYM | 62 | 64 SO | 66 |
| 68 | 6A | 6C | 6E |
| 70 | 72 | 74 | 76 |
| 78 | 7A | 7C | 7E |
| 80 LSYM | 82 BINCL | 84 SOL | 86 |
| 88 | 8A | 8C | 8E |
| 90 | 92 | 94 | 96 |
| 98 | 9A | 9C | 9E |
| A0 PSYM | A2 EINCL | A4 ENTRY | A6 |
| A8 | AA | AC | AE |
| B0 | B2 | B4 | B6 |
| B8 | BA | BC | BE |
| C0 LBRAC | C2 EXCL | C4 SCOPE | C6 |
| C8 | CA | CC | CE |
| D0 | D2 | D4 | D6 |
| D8 | DA | DC | DE |
| E0 RBRAC | E2 BCOMM | E4 ECOMM | E6 |
| E8 ECOML | EA | EC | EE |
| F0 | F2 | F4 | F6 |
| F8 | FA | FC | FE LENG |
+-----------------------------------------------+
* 50 EHDECL is also MOD2.
* 48 BSLINE is also BROWS.
*/
+17
View File
@@ -0,0 +1,17 @@
#ifndef __GNU_STAB__
/* Indicate the GNU stab.h is in use. */
#define __GNU_STAB__
#define __define_stab(NAME, CODE, STRING) NAME=CODE,
enum __stab_debug_code
{
#include "stab.def"
LAST_UNUSED_STAB_CODE
};
#undef __define_stab
#endif /* __GNU_STAB_ */
+448
View File
@@ -0,0 +1,448 @@
/*
* 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
#include "tcc.h"
#if ONE_SOURCE
# include "libtcc.c"
#endif
#include "tcctools.c"
static const char help[] =
"Tiny C Compiler "TCC_VERSION" - Copyright (C) 2001-2006 Fabrice Bellard\n"
"Usage: tcc [options...] [-o outfile] [-c] infile(s)...\n"
" tcc [options...] -run infile (or --) [arguments...]\n"
"General options:\n"
" -c compile only - generate an object file\n"
" -o outfile set output filename\n"
" -run run compiled source [with custom stdin: -rstdin FILE]\n"
" -fflag set or reset (with 'no-' prefix) 'flag' (see tcc -hh)\n"
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n"
" -w disable all warnings\n"
" -v --version show version\n"
" -vv show search paths or loaded files\n"
" -h -hh show this, show more help\n"
" -bench show compilation statistics\n"
" - use stdin pipe as infile\n"
" @listfile read arguments from listfile\n"
"Preprocessor options:\n"
" -Idir add include path 'dir'\n"
" -Dsym[=val] define 'sym' with value 'val'\n"
" -Usym undefine 'sym'\n"
" -E preprocess only\n"
" -nostdinc do not use standard system include paths\n"
"Linker options:\n"
" -Ldir add library path 'dir'\n"
" -llib link with dynamic or static library 'lib'\n"
" -nostdlib do not link with standard crt and libraries\n"
" -r generate (relocatable) object file\n"
" -rdynamic export all global symbols to dynamic linker\n"
" -shared generate a shared library/dll\n"
" -soname set name for shared library to be used at runtime\n"
" -Wl,-opt[=val] set linker option (see tcc -hh)\n"
"Debugger options:\n"
" -g generate stab runtime debug info\n"
" -gdwarf[-x] generate dwarf runtime debug info\n"
#ifdef TCC_TARGET_PE
" -g.pdb create .pdb debug database\n"
#endif
#ifdef CONFIG_TCC_BCHECK
" -b compile with built-in memory and bounds checker (implies -g)\n"
#endif
#ifdef CONFIG_TCC_BACKTRACE
" -bt[N] link with backtrace (stack dump) support [show max N callers]\n"
#endif
"Misc. options:\n"
" -std=version define __STDC_VERSION__ according to version (c11/gnu11)\n"
" -x[c|a|b|n] specify type of the next infile (C,ASM,BIN,NONE)\n"
" -Bdir set tcc's private include/library dir\n"
" -M[M]D generate make dependency file [ignore system files]\n"
" -M[M] as above but no other output\n"
" -MF file specify dependency file name\n"
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
" -m32/64 defer to i386/x86_64 cross compiler\n"
#endif
"Tools:\n"
" create library : tcc -ar [crstvx] lib [files]\n"
#ifdef TCC_TARGET_PE
" create def file : tcc -impdef lib.dll [-v] [-o lib.def]\n"
#endif
"Discussion & bug reports:\n"
" https://lists.nongnu.org/mailman/listinfo/tinycc-devel\n"
;
static const char help2[] =
"Tiny C Compiler "TCC_VERSION" - More Options\n"
"Special options:\n"
" -P -P1 with -E: no/alternative #line output\n"
" -dD -dM with -E: output #define directives\n"
" -pthread same as -D_REENTRANT and -lpthread\n"
" -On same as -D__OPTIMIZE__ for n > 0\n"
" -Wp,-opt same as -opt\n"
" -include file include 'file' above each input file\n"
" -nostdlib do not link with standard crt/libs\n"
" -isystem dir add 'dir' to system include path\n"
" -static link to static libraries (not recommended)\n"
" -dumpversion print version\n"
" -print-search-dirs print search paths\n"
" -dt with -run/-E: auto-define 'test_...' macros\n"
"Ignored options:\n"
" -arch -C --param -pedantic -pipe -s -traditional\n"
"-W[no-]... warnings:\n"
" all turn on some (*) warnings\n"
" error[=warning] stop after warning (any or specified)\n"
" write-strings strings are const\n"
" unsupported warn about ignored options, pragmas, etc.\n"
" implicit-function-declaration warn for missing prototype (*)\n"
" discarded-qualifiers warn when const is dropped (*)\n"
"-f[no-]... flags:\n"
" unsigned-char default char is unsigned\n"
" signed-char default char is signed\n"
" common use common section instead of bss\n"
" leading-underscore decorate extern symbols\n"
" ms-extensions allow anonymous struct in struct\n"
" dollars-in-identifiers allow '$' in C symbols\n"
" reverse-funcargs evaluate function arguments right to left\n"
" gnu89-inline 'extern inline' is like 'static inline'\n"
" asynchronous-unwind-tables create eh_frame section [on]\n"
" test-coverage create code coverage code\n"
"-m... target specific options:\n"
" ms-bitfields use MSVC bitfield layout\n"
#ifdef TCC_TARGET_ARM
" float-abi hard/softfp on arm\n"
#endif
#ifdef TCC_TARGET_X86_64
" no-sse disable floats on x86_64\n"
#endif
"-Wl,... linker options:\n"
" -nostdlib do not search standard library paths\n"
" -[no-]whole-archive load lib(s) fully/only as needed\n"
" -export-all-symbols same as -rdynamic\n"
" -export-dynamic same as -rdynamic\n"
" -image-base= -Ttext= set base address of executable\n"
" -section-alignment= set section alignment in executable\n"
#ifdef TCC_TARGET_PE
" -file-alignment= set PE file alignment\n"
" -stack= set PE stack reserve\n"
" -large-address-aware set related PE option\n"
" -subsystem=[console/windows] set PE subsystem\n"
" -oformat=[pe-* binary] set executable output format\n"
"Predefined macros:\n"
" tcc -E -dM - < nul\n"
#else
" -rpath= set dynamic library search path\n"
" -enable-new-dtags set DT_RUNPATH instead of DT_RPATH\n"
" -soname= set DT_SONAME elf tag\n"
#if defined(TCC_TARGET_MACHO)
" -install_name= set DT_SONAME elf tag (soname macOS alias)\n"
#else
" -Ipath, -dynamic-linker=path set ELF interpreter to path\n"
#endif
" -Bsymbolic set DT_SYMBOLIC elf tag\n"
" -oformat=[elf32/64-* binary] set executable output format\n"
" -init= -fini= -Map= -as-needed -O -z= (ignored)\n"
"Predefined macros:\n"
" tcc -E -dM - < /dev/null\n"
#endif
"See also the manual for more details.\n"
;
static const char version[] =
"tcc version "TCC_VERSION
#ifdef TCC_GITHASH
" "TCC_GITHASH
#endif
" ("
#ifdef TCC_TARGET_I386
"i386"
#elif defined TCC_TARGET_X86_64
"x86_64"
#elif defined TCC_TARGET_C67
"C67"
#elif defined TCC_TARGET_ARM
"ARM"
# ifdef TCC_ARM_EABI
" eabi"
# ifdef TCC_ARM_HARDFLOAT
"hf"
# endif
# endif
#elif defined TCC_TARGET_ARM64
"AArch64"
#elif defined TCC_TARGET_RISCV64
"riscv64"
#endif
#ifdef TCC_TARGET_PE
" Windows"
#elif defined(TCC_TARGET_MACHO)
" Darwin"
#elif TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel
" FreeBSD"
#elif TARGETOS_OpenBSD
" OpenBSD"
#elif TARGETOS_NetBSD
" NetBSD"
#else
" Linux"
#endif
")\n"
;
static void print_dirs(const char *msg, char **paths, int nb_paths)
{
int i;
printf("%s:\n%s", msg, nb_paths ? "" : " -\n");
for(i = 0; i < nb_paths; i++)
printf(" %s\n", paths[i]);
}
static void print_search_dirs(TCCState *s)
{
printf("install: %s\n", s->tcc_lib_path);
/* print_dirs("programs", NULL, 0); */
print_dirs("include", s->sysinclude_paths, s->nb_sysinclude_paths);
print_dirs("libraries", s->library_paths, s->nb_library_paths);
printf("libtcc1:\n %s/%s\n", s->library_paths[0], CONFIG_TCC_CROSSPREFIX TCC_LIBTCC1);
#ifdef TCC_TARGET_UNIX
print_dirs("crt", s->crt_paths, s->nb_crt_paths);
printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s));
#endif
}
static void set_environment(TCCState *s)
{
char * path;
path = getenv("C_INCLUDE_PATH");
if(path != NULL) {
tcc_add_sysinclude_path(s, path);
}
path = getenv("CPATH");
if(path != NULL) {
tcc_add_include_path(s, path);
}
path = getenv("LIBRARY_PATH");
if(path != NULL) {
tcc_add_library_path(s, path);
}
}
static char *default_outputfile(TCCState *s, const char *first_file)
{
char buf[1024];
char *ext;
const char *name = "a";
if (first_file && strcmp(first_file, "-"))
name = tcc_basename(first_file);
if (strlen(name) + 4 >= sizeof buf)
name = "a";
strcpy(buf, name);
ext = tcc_fileextension(buf);
#ifdef TCC_TARGET_PE
if (s->output_type == TCC_OUTPUT_DLL)
strcpy(ext, ".dll");
else
if (s->output_type == TCC_OUTPUT_EXE)
strcpy(ext, ".exe");
else
#endif
if ((s->just_deps || s->output_type == TCC_OUTPUT_OBJ) && !s->option_r && *ext)
strcpy(ext, ".o");
else {
#ifdef __MONTAUKOS__
strcpy(ext, ".elf");
#else
strcpy(buf, "a.out");
#endif
}
#ifdef __MONTAUKOS__
/* MontaukOS requires absolute paths (N:/...). If the result is
relative, derive the directory from the first input file. */
if (!IS_ABSPATH(buf) && first_file && IS_ABSPATH(first_file)) {
char abs[1024];
const char *base = tcc_basename(first_file);
int dirlen = (int)(base - first_file);
if (dirlen + (int)strlen(buf) + 1 < (int)sizeof(abs)) {
memcpy(abs, first_file, dirlen);
strcpy(abs + dirlen, buf);
return tcc_strdup(abs);
}
}
#endif
return tcc_strdup(buf);
}
static unsigned getclock_ms(void)
{
#ifdef _WIN32
return GetTickCount();
#else
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec*1000 + (tv.tv_usec+500)/1000;
#endif
}
int main(int argc, char **argv)
{
TCCState *s, *s1;
int ret, opt, n = 0, t = 0, done;
unsigned start_time = 0, end_time = 0;
const char *first_file;
int argc0 = argc;
char **argv0 = argv;
FILE *ppfp = stdout;
redo:
argc = argc0, argv = argv0;
s = s1 = tcc_new();
opt = tcc_parse_args(s, &argc, &argv);
if (n == 0) {
ret = 0;
if (opt == OPT_HELP) {
fputs(help, stdout);
if (s->verbose)
goto help2;
} else if (opt == OPT_HELP2) {
help2: fputs(help2, stdout);
} else if (opt == OPT_M32 || opt == OPT_M64) {
ret = tcc_tool_cross(argv, opt);
} else if (s->verbose)
printf("%s", version);
if (opt == OPT_AR)
ret = tcc_tool_ar(argc, argv);
#ifdef TCC_TARGET_PE
if (opt == OPT_IMPDEF)
ret = tcc_tool_impdef(argc, argv);
#endif
if (opt == OPT_PRINT_DIRS) {
/* initialize search dirs */
set_environment(s);
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
print_search_dirs(s);
}
if (opt) {
if (opt < 0) err:
ret = 1;
tcc_delete(s);
return ret;
}
if (s->nb_files == 0) {
tcc_error_noabort("no input files");
} else if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (s->outfile && 0!=strcmp("-",s->outfile)) {
ppfp = fopen(s->outfile, "wb");
if (!ppfp)
tcc_error_noabort("could not write '%s'", s->outfile);
}
} else if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r) {
if (s->nb_libraries)
tcc_error_noabort("cannot specify libraries with -c");
else if (s->nb_files > 1 && s->outfile)
tcc_error_noabort("cannot specify output file with -c many files");
}
if (s->nb_errors)
goto err;
if (s->do_bench)
start_time = getclock_ms();
}
set_environment(s);
if (s->output_type == 0)
s->output_type = TCC_OUTPUT_EXE;
tcc_set_output_type(s, s->output_type);
s->ppfp = ppfp;
if ((s->output_type == TCC_OUTPUT_MEMORY
|| s->output_type == TCC_OUTPUT_PREPROCESS)
&& (s->dflag & 16)) { /* -dt option */
if (t)
s->dflag |= 32;
s->run_test = ++t;
if (n)
--n;
}
/* compile or add each files or library */
first_file = NULL;
do {
struct filespec *f = s->files[n];
s->filetype = f->type;
if (f->type & AFF_TYPE_LIB) {
ret = tcc_add_library(s, f->name);
} else {
if (1 == s->verbose)
printf("-> %s\n", f->name);
if (!first_file)
first_file = f->name;
ret = tcc_add_file(s, f->name);
}
} while (++n < s->nb_files
&& 0 == ret
&& (s->output_type != TCC_OUTPUT_OBJ || s->option_r));
if (s->do_bench)
end_time = getclock_ms();
if (s->run_test) {
t = 0;
} else if (s->output_type == TCC_OUTPUT_PREPROCESS) {
;
} else if (0 == ret) {
if (s->output_type == TCC_OUTPUT_MEMORY) {
#ifdef TCC_IS_NATIVE
ret = tcc_run(s, argc, argv);
#endif
} else {
if (!s->outfile)
s->outfile = default_outputfile(s, first_file);
if (!s->just_deps)
ret = tcc_output_file(s, s->outfile);
if (!ret && s->gen_deps)
gen_makedeps(s, s->outfile, s->deps_outfile);
}
}
done = 1;
if (t)
done = 0; /* run more tests with -dt -run */
else if (ret) {
if (s->nb_errors)
ret = 1;
/* else keep the original exit code from tcc_run() */
} else if (n < s->nb_files)
done = 0; /* compile more files with -c */
else if (s->do_bench)
tcc_print_stats(s, end_time - start_time);
tcc_delete(s);
if (!done)
goto redo;
if (ppfp && ppfp != stdout)
fclose(ppfp);
return ret;
}
File diff suppressed because it is too large Load Diff
+75
View File
@@ -0,0 +1,75 @@
#ifndef _FLOAT_H_
#define _FLOAT_H_
#define FLT_RADIX 2
/* IEEE float */
#define FLT_MANT_DIG 24
#define FLT_DIG 6
#define FLT_ROUNDS 1
#define FLT_EPSILON 1.19209290e-07F
#define FLT_MIN_EXP (-125)
#define FLT_MIN 1.17549435e-38F
#define FLT_MIN_10_EXP (-37)
#define FLT_MAX_EXP 128
#define FLT_MAX 3.40282347e+38F
#define FLT_MAX_10_EXP 38
/* IEEE double */
#define DBL_MANT_DIG 53
#define DBL_DIG 15
#define DBL_EPSILON 2.2204460492503131e-16
#define DBL_MIN_EXP (-1021)
#define DBL_MIN 2.2250738585072014e-308
#define DBL_MIN_10_EXP (-307)
#define DBL_MAX_EXP 1024
#define DBL_MAX 1.7976931348623157e+308
#define DBL_MAX_10_EXP 308
/* horrible intel long double */
#if defined __i386__ || defined __x86_64__
#define LDBL_MANT_DIG 64
#define LDBL_DIG 18
#define LDBL_EPSILON 1.08420217248550443401e-19L
#define LDBL_MIN_EXP (-16381)
#define LDBL_MIN 3.36210314311209350626e-4932L
#define LDBL_MIN_10_EXP (-4931)
#define LDBL_MAX_EXP 16384
#define LDBL_MAX 1.18973149535723176502e+4932L
#define LDBL_MAX_10_EXP 4932
#define DECIMAL_DIG 21
#elif defined __aarch64__ || defined __riscv
/*
* Use values from:
* gcc -dM -E -xc /dev/null | grep LDBL | sed -e "s/__//g"
*/
#define LDBL_MANT_DIG 113
#define LDBL_DIG 33
#define LDBL_EPSILON 1.92592994438723585305597794258492732e-34L
#define LDBL_MIN_EXP (-16381)
#define LDBL_MIN 3.36210314311209350626267781732175260e-4932L
#define LDBL_MIN_10_EXP (-4931)
#define LDBL_MAX_EXP 16384
#define LDBL_MAX 1.18973149535723176508575932662800702e+4932L
#define LDBL_MAX_10_EXP 4932
#define DECIMAL_DIG 36
#else
/* same as IEEE double */
#define LDBL_MANT_DIG 53
#define LDBL_DIG 15
#define LDBL_EPSILON 2.2204460492503131e-16L
#define LDBL_MIN_EXP (-1021)
#define LDBL_MIN 2.2250738585072014e-308L
#define LDBL_MIN_10_EXP (-307)
#define LDBL_MAX_EXP 1024
#define LDBL_MAX 1.7976931348623157e+308L
#define LDBL_MAX_10_EXP 308
#define DECIMAL_DIG 17
#endif
#endif /* _FLOAT_H_ */
+16
View File
@@ -0,0 +1,16 @@
#ifndef _STDALIGN_H
#define _STDALIGN_H
#if __STDC_VERSION__ < 201112L && (defined(__GNUC__) || defined(__TINYC__))
# define _Alignas(t) __attribute__((__aligned__(t)))
# define _Alignof(t) __alignof__(t)
#endif
#define alignas _Alignas
#define alignof _Alignof
#define __alignas_is_defined 1
#define __alignof_is_defined 1
#endif /* _STDALIGN_H */
+14
View File
@@ -0,0 +1,14 @@
#ifndef _STDARG_H
#define _STDARG_H
typedef __builtin_va_list va_list;
#define va_start __builtin_va_start
#define va_arg __builtin_va_arg
#define va_copy __builtin_va_copy
#define va_end __builtin_va_end
/* fix a buggy dependency on GCC in libio.h */
typedef va_list __gnuc_va_list;
#define _VA_LIST_DEFINED
#endif /* _STDARG_H */
+171
View File
@@ -0,0 +1,171 @@
/* This file is derived from clang's stdatomic.h */
/*===---- stdatomic.h - Standard header for atomic types and operations -----===
*
* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
* See https://llvm.org/LICENSE.txt for license information.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*
*===-----------------------------------------------------------------------===
*/
#ifndef _STDATOMIC_H
#define _STDATOMIC_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#define __ATOMIC_RELAXED 0
#define __ATOMIC_CONSUME 1
#define __ATOMIC_ACQUIRE 2
#define __ATOMIC_RELEASE 3
#define __ATOMIC_ACQ_REL 4
#define __ATOMIC_SEQ_CST 5
/* Memory ordering */
typedef enum {
memory_order_relaxed = __ATOMIC_RELAXED,
memory_order_consume = __ATOMIC_CONSUME,
memory_order_acquire = __ATOMIC_ACQUIRE,
memory_order_release = __ATOMIC_RELEASE,
memory_order_acq_rel = __ATOMIC_ACQ_REL,
memory_order_seq_cst = __ATOMIC_SEQ_CST,
} memory_order;
/* Atomic typedefs */
typedef _Atomic(_Bool) atomic_bool;
typedef _Atomic(char) atomic_char;
typedef _Atomic(signed char) atomic_schar;
typedef _Atomic(unsigned char) atomic_uchar;
typedef _Atomic(short) atomic_short;
typedef _Atomic(unsigned short) atomic_ushort;
typedef _Atomic(int) atomic_int;
typedef _Atomic(unsigned int) atomic_uint;
typedef _Atomic(long) atomic_long;
typedef _Atomic(unsigned long) atomic_ulong;
typedef _Atomic(long long) atomic_llong;
typedef _Atomic(unsigned long long) atomic_ullong;
typedef _Atomic(uint_least16_t) atomic_char16_t;
typedef _Atomic(uint_least32_t) atomic_char32_t;
typedef _Atomic(wchar_t) atomic_wchar_t;
typedef _Atomic(int_least8_t) atomic_int_least8_t;
typedef _Atomic(uint_least8_t) atomic_uint_least8_t;
typedef _Atomic(int_least16_t) atomic_int_least16_t;
typedef _Atomic(uint_least16_t) atomic_uint_least16_t;
typedef _Atomic(int_least32_t) atomic_int_least32_t;
typedef _Atomic(uint_least32_t) atomic_uint_least32_t;
typedef _Atomic(int_least64_t) atomic_int_least64_t;
typedef _Atomic(uint_least64_t) atomic_uint_least64_t;
typedef _Atomic(int_fast8_t) atomic_int_fast8_t;
typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t;
typedef _Atomic(int_fast16_t) atomic_int_fast16_t;
typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t;
typedef _Atomic(int_fast32_t) atomic_int_fast32_t;
typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t;
typedef _Atomic(int_fast64_t) atomic_int_fast64_t;
typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t;
typedef _Atomic(intptr_t) atomic_intptr_t;
typedef _Atomic(uintptr_t) atomic_uintptr_t;
typedef _Atomic(size_t) atomic_size_t;
typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
typedef _Atomic(intmax_t) atomic_intmax_t;
typedef _Atomic(uintmax_t) atomic_uintmax_t;
/* Atomic flag */
typedef struct {
atomic_bool value;
} atomic_flag;
#define ATOMIC_FLAG_INIT {0}
#define ATOMIC_VAR_INIT(value) (value)
/* Generic routines */
#define atomic_init(object, desired) \
atomic_store_explicit(object, desired, __ATOMIC_RELAXED)
#define __atomic_store_n(ptr, val, order) \
(*(ptr) = (val), __atomic_store((ptr), &(typeof(*(ptr))){val}, (order)))
#define atomic_store_explicit(object, desired, order) \
({ __typeof__ (object) ptr = (object); \
__typeof__ (*ptr) tmp = (desired); \
__atomic_store (ptr, &tmp, (order)); \
})
#define atomic_store(object, desired) \
atomic_store_explicit (object, desired, __ATOMIC_SEQ_CST)
#define __atomic_load_n(ptr, order) \
({ typeof(*(ptr)) __val; \
__atomic_load((ptr), &__val, (order)); \
__val; })
#define atomic_load_explicit(object, order) \
({ __typeof__ (object) ptr = (object); \
__typeof__ (*ptr) tmp; \
__atomic_load (ptr, &tmp, (order)); \
tmp; \
})
#define atomic_load(object) atomic_load_explicit (object, __ATOMIC_SEQ_CST)
#define atomic_exchange_explicit(object, desired, order) \
({ __typeof__ (object) ptr = (object); \
__typeof__ (*ptr) val = (desired); \
__typeof__ (*ptr) tmp; \
__atomic_exchange (ptr, &val, &tmp, (order)); \
tmp; \
})
#define atomic_exchange(object, desired) \
atomic_exchange_explicit (object, desired, __ATOMIC_SEQ_CST)
#define __atomic_compare_exchange_n(ptr, expected, desired, weak, success, failure) \
({ typeof(*(ptr)) __desired = (desired); \
__atomic_compare_exchange((ptr), (expected), &__desired, \
(weak), (success), (failure)); })
#define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure) \
({ __typeof__ (object) ptr = (object); \
__typeof__ (*ptr) tmp = desired; \
__atomic_compare_exchange(ptr, expected, &tmp, 0, success, failure); \
})
#define atomic_compare_exchange_strong(object, expected, desired) \
atomic_compare_exchange_strong_explicit (object, expected, desired, \
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
#define atomic_compare_exchange_weak_explicit(object, expected, desired, success, failure) \
({ __typeof__ (object) ptr = (object); \
__typeof__ (*ptr) tmp = desired; \
__atomic_compare_exchange(ptr, expected, &tmp, 1, success, failure); \
})
#define atomic_compare_exchange_weak(object, expected, desired) \
atomic_compare_exchange_weak_explicit (object, expected, desired, \
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
#define atomic_fetch_add(object, operand) \
__atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST)
#define atomic_fetch_add_explicit __atomic_fetch_add
#define atomic_fetch_sub(object, operand) \
__atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST)
#define atomic_fetch_sub_explicit __atomic_fetch_sub
#define atomic_fetch_or(object, operand) \
__atomic_fetch_or(object, operand, __ATOMIC_SEQ_CST)
#define atomic_fetch_or_explicit __atomic_fetch_or
#define atomic_fetch_xor(object, operand) \
__atomic_fetch_xor(object, operand, __ATOMIC_SEQ_CST)
#define atomic_fetch_xor_explicit __atomic_fetch_xor
#define atomic_fetch_and(object, operand) \
__atomic_fetch_and(object, operand, __ATOMIC_SEQ_CST)
#define atomic_fetch_and_explicit __atomic_fetch_and
extern void atomic_thread_fence (memory_order);
#define __atomic_thread_fence(order) atomic_thread_fence (order)
extern void atomic_signal_fence (memory_order);
#define __atomic_signal_fence(order) atomic_signal_fence(order)
#define atomic_signal_fence(order) __atomic_signal_fence (order)
extern bool __atomic_is_lock_free(size_t size, void *ptr);
#define atomic_is_lock_free(OBJ) __atomic_is_lock_free (sizeof (*(OBJ)), (OBJ))
extern bool atomic_flag_test_and_set(void *object);
extern bool atomic_flag_test_and_set_explicit(void *object, memory_order order);
extern void atomic_flag_clear(void *object);
extern void atomic_flag_clear_explicit(void *object, memory_order order);
#endif /* _STDATOMIC_H */
+11
View File
@@ -0,0 +1,11 @@
#ifndef _STDBOOL_H
#define _STDBOOL_H
/* ISOC99 boolean */
#define bool _Bool
#define true 1
#define false 0
#define __bool_true_false_are_defined 1
#endif /* _STDBOOL_H */
+39
View File
@@ -0,0 +1,39 @@
#ifndef _STDDEF_H
#define _STDDEF_H
typedef __SIZE_TYPE__ size_t;
typedef __PTRDIFF_TYPE__ ssize_t;
typedef __WCHAR_TYPE__ wchar_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef __PTRDIFF_TYPE__ intptr_t;
typedef __SIZE_TYPE__ uintptr_t;
#if __STDC_VERSION__ >= 201112L
typedef union { long long __ll; long double __ld; } max_align_t;
#endif
#ifndef NULL
#define NULL ((void*)0)
#endif
#undef offsetof
#define offsetof(type, field) __builtin_offsetof(type, field)
void *alloca(size_t size);
#endif
/* Older glibc require a wint_t from <stddef.h> (when requested
by __need_wint_t, as otherwise stddef.h isn't allowed to
define this type). Note that this must be outside the normal
_STDDEF_H guard, so that it works even when we've included the file
already (without requiring wint_t). Some other libs define _WINT_T
if they've already provided that type, so we can use that as guard.
TCC defines __WINT_TYPE__ for us. */
#if defined (__need_wint_t)
#ifndef _WINT_T
#define _WINT_T
typedef __WINT_TYPE__ wint_t;
#endif
#undef __need_wint_t
#endif
@@ -0,0 +1,7 @@
#ifndef _STDNORETURN_H
#define _STDNORETURN_H
/* ISOC11 noreturn */
#define noreturn _Noreturn
#endif /* _STDNORETURN_H */
+377
View File
@@ -0,0 +1,377 @@
/* tccdefs.h
Nothing is defined before this file except target machine, target os
and the few things related to option settings in tccpp.c:tcc_predefs().
This file is either included at runtime as is, or converted and
included as C-strings at compile-time (depending on CONFIG_TCC_PREDEFS).
Note that line indent matters:
- in lines starting at column 1, platform macros are replaced by
corresponding TCC target compile-time macros. See conftest.c for
the list of platform macros supported in lines starting at column 1.
- only lines indented >= 4 are actually included into the executable,
check tccdefs_.h.
*/
#if __SIZEOF_POINTER__ == 4
/* 32bit systems. */
#if defined __OpenBSD__
#define __SIZE_TYPE__ unsigned long
#define __PTRDIFF_TYPE__ long
#else
#define __SIZE_TYPE__ unsigned int
#define __PTRDIFF_TYPE__ int
#endif
#define __ILP32__ 1
#define __INT64_TYPE__ long long
#elif __SIZEOF_LONG__ == 4
/* 64bit Windows. */
#define __SIZE_TYPE__ unsigned long long
#define __PTRDIFF_TYPE__ long long
#define __LLP64__ 1
#define __INT64_TYPE__ long long
#else
/* Other 64bit systems. */
#define __SIZE_TYPE__ unsigned long
#define __PTRDIFF_TYPE__ long
#define __LP64__ 1
# if defined __linux__
#define __INT64_TYPE__ long
# else /* APPLE, BSD */
#define __INT64_TYPE__ long long
# endif
#endif
#define __SIZEOF_INT__ 4
#define __INT_MAX__ 0x7fffffff
#if __SIZEOF_LONG__ == 4
#define __LONG_MAX__ 0x7fffffffL
#else
#define __LONG_MAX__ 0x7fffffffffffffffL
#endif
#define __SIZEOF_LONG_LONG__ 8
#define __LONG_LONG_MAX__ 0x7fffffffffffffffLL
#define __CHAR_BIT__ 8
#define __ORDER_LITTLE_ENDIAN__ 1234
#define __ORDER_BIG_ENDIAN__ 4321
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
#if defined _WIN32
#define __WCHAR_TYPE__ unsigned short
#define __WINT_TYPE__ unsigned short
#elif defined __linux__
#define __WCHAR_TYPE__ int
#define __WINT_TYPE__ unsigned int
#else
#define __WCHAR_TYPE__ int
#define __WINT_TYPE__ int
#endif
#if __STDC_VERSION__ >= 201112L
# define __STDC_NO_ATOMICS__ 1
# define __STDC_NO_COMPLEX__ 1
# define __STDC_NO_THREADS__ 1
#if !defined _WIN32
# define __STDC_UTF_16__ 1
# define __STDC_UTF_32__ 1
#endif
#endif
#if defined _WIN32
#define __declspec(x) __attribute__((x))
#define __cdecl
#elif defined __FreeBSD__
#define __GNUC__ 9
#define __GNUC_MINOR__ 3
#define __GNUC_PATCHLEVEL__ 0
#define __GNUC_STDC_INLINE__ 1
#define __NO_TLS 1
#define __RUNETYPE_INTERNAL 1
# if __SIZEOF_POINTER__ == 8
/* FIXME, __int128_t is used by setjump */
#define __int128_t struct { unsigned char _dummy[16] __attribute((aligned(16))); }
#define __SIZEOF_SIZE_T__ 8
#define __SIZEOF_PTRDIFF_T__ 8
#else
#define __SIZEOF_SIZE_T__ 4
#define __SIZEOF_PTRDIFF_T__ 4
# endif
#elif defined __FreeBSD_kernel__
#elif defined __NetBSD__
#define __GNUC__ 4
#define __GNUC_MINOR__ 1
#define __GNUC_PATCHLEVEL__ 0
#define _Pragma(x)
#define __ELF__ 1
#if defined __aarch64__
#define _LOCORE /* avoids usage of __asm */
#endif
#elif defined __OpenBSD__
#define __GNUC__ 4
#define _ANSI_LIBRARY 1
#elif defined __APPLE__
/* emulate APPLE-GCC to make libc's headerfiles compile: */
#define __GNUC__ 4 /* darwin emits warning on GCC<4 */
#define __APPLE_CC__ 1 /* for <TargetConditionals.h> */
#define __LITTLE_ENDIAN__ 1
#define _DONT_USE_CTYPE_INLINE_ 1
/* avoids usage of GCC/clang specific builtins in libc-headerfiles: */
#define __FINITE_MATH_ONLY__ 1
#define _FORTIFY_SOURCE 0
//#define __has_builtin(x) 0
#define _Float16 short unsigned int /* fake type just for size & alignment (macOS Sequoia) */
#elif defined __ANDROID__
#define BIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD
#else
/* Linux */
#endif
/* Some derived integer types needed to get stdint.h to compile correctly on some platforms */
#ifndef __NetBSD__
#define __UINTPTR_TYPE__ unsigned __PTRDIFF_TYPE__
#define __INTPTR_TYPE__ __PTRDIFF_TYPE__
#endif
#define __INT32_TYPE__ int
#if defined __aarch64__
/* GCC's __uint128_t appears in some Linux/OSX header files. Make it a
synonym for long double to get the size and alignment right. */
#define __uint128_t long double
#endif
#if !defined _WIN32
/* glibc defines. We do not support __USER_NAME_PREFIX__ */
#define __REDIRECT(name, proto, alias) name proto __asm__ (#alias)
#define __REDIRECT_NTH(name, proto, alias) name proto __asm__ (#alias) __THROW
#define __REDIRECT_NTHNL(name, proto, alias) name proto __asm__ (#alias) __THROWNL
#endif
/* not implemented */
#define __PRETTY_FUNCTION__ __FUNCTION__
#define __has_builtin(x) 0
#define __has_feature(x) 0
#define __has_attribute(x) 0
/* C23 Keywords */
#define _Nonnull
#define _Nullable
#define _Nullable_result
#define _Null_unspecified
/* skip __builtin... with -E */
#ifndef __TCC_PP__
#define __builtin_offsetof(type, field) ((__SIZE_TYPE__)&((type*)0)->field)
#define __builtin_extract_return_addr(x) x
#if !defined __linux__ && !defined _WIN32
/* used by math.h */
#define __builtin_huge_val() 1e500
#define __builtin_huge_valf() 1e50f
#define __builtin_huge_vall() 1e5000L
# if defined __APPLE__
#define __builtin_nanf(ignored_string) (0.0F/0.0F)
/* used by floats.h to implement FLT_ROUNDS C99 macro. 1 == to nearest */
#define __builtin_flt_rounds() 1
/* used by _fd_def.h */
#define __builtin_bzero(p, ignored_size) bzero(p, sizeof(*(p)))
# else
#define __builtin_nanf(ignored_string) (0.0F/0.0F)
# endif
#endif
/* __builtin_va_list */
#if defined __x86_64__
#if !defined _WIN32
/* GCC compatible definition of va_list. */
enum __va_arg_type {
__va_gen_reg, __va_float_reg, __va_stack
};
typedef struct {
unsigned gp_offset, fp_offset;
union {
unsigned overflow_offset;
char *overflow_arg_area;
};
char *reg_save_area;
} __builtin_va_list[1];
static inline void *__va_arg(__builtin_va_list ap, int arg_type,
int size, int align)
{
size = (size + 7) & ~7;
align = (align + 7) & ~7;
switch ((enum __va_arg_type)arg_type) {
case __va_gen_reg:
if (ap->gp_offset + size <= 48) {
ap->gp_offset += size;
return ap->reg_save_area + ap->gp_offset - size;
}
goto use_overflow_area;
case __va_float_reg:
if (ap->fp_offset < 128 + 48) {
ap->fp_offset += 16;
if (size == 8)
return ap->reg_save_area + ap->fp_offset - 16;
if (ap->fp_offset < 128 + 48) {
double *p = (double *)(ap->reg_save_area + ap->fp_offset);
p[-1] = p[0];
ap->fp_offset += 16;
return ap->reg_save_area + ap->fp_offset - 32;
}
}
goto use_overflow_area;
case __va_stack:
use_overflow_area:
ap->overflow_arg_area += size;
ap->overflow_arg_area =
(char*)((long long)(ap->overflow_arg_area + align - 1) & -align);
return ap->overflow_arg_area - size;
default: /* should never happen */
char *a = (char *)0; *a = 0; // abort
return 0;
}
}
#define __builtin_va_start(ap, last) \
(*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24))
#define __builtin_va_arg(ap, t) \
(*(t *)(__va_arg(ap, __builtin_va_arg_types(t), sizeof(t), __alignof__(t))))
#define __builtin_va_copy(dest, src) (*(dest) = *(src))
#else /* _WIN64 */
typedef char *__builtin_va_list;
#define __builtin_va_arg(ap, t) ((sizeof(t) > 8 || (sizeof(t) & (sizeof(t) - 1))) \
? **(t **)((ap += 8) - 8) : *(t *)((ap += 8) - 8))
#endif
#elif defined __arm__
typedef char *__builtin_va_list;
#define _tcc_alignof(type) ((int)&((struct {char c;type x;} *)0)->x)
#define _tcc_align(addr,type) (((unsigned)addr + _tcc_alignof(type) - 1) \
& ~(_tcc_alignof(type) - 1))
#define __builtin_va_start(ap,last) (ap = ((char *)&(last)) + ((sizeof(last)+3)&~3))
#define __builtin_va_arg(ap,type) (ap = (void *) ((_tcc_align(ap,type)+sizeof(type)+3) \
&~3), *(type *)(ap - ((sizeof(type)+3)&~3)))
#elif defined __aarch64__
#if defined __APPLE__
typedef struct {
void *__stack;
} __builtin_va_list;
#else
typedef struct {
void *__stack, *__gr_top, *__vr_top;
int __gr_offs, __vr_offs;
} __builtin_va_list;
#endif
#elif defined __riscv
typedef char *__builtin_va_list;
#define __va_reg_size (__riscv_xlen >> 3)
#define _tcc_align(addr,type) (((unsigned long)addr + __alignof__(type) - 1) \
& -(__alignof__(type)))
#define __builtin_va_arg(ap,type) (*(sizeof(type) > (2*__va_reg_size) ? *(type **)((ap += __va_reg_size) - __va_reg_size) : (ap = (va_list)(_tcc_align(ap,type) + (sizeof(type)+__va_reg_size - 1)& -__va_reg_size), (type *)(ap - ((sizeof(type)+ __va_reg_size - 1)& -__va_reg_size)))))
#else /* __i386__ */
typedef char *__builtin_va_list;
#define __builtin_va_start(ap,last) (ap = ((char *)&(last)) + ((sizeof(last)+3)&~3))
#define __builtin_va_arg(ap,t) (*(t*)((ap+=(sizeof(t)+3)&~3)-((sizeof(t)+3)&~3)))
#endif
#define __builtin_va_end(ap) (void)(ap)
#ifndef __builtin_va_copy
# define __builtin_va_copy(dest, src) (dest) = (src)
#endif
/* TCC BBUILTIN AND BOUNDS ALIASES */
#ifdef __leading_underscore
# define __RENAME(X) __asm__("_"X)
#else
# define __RENAME(X) __asm__(X)
#endif
#ifdef __TCC_BCHECK__
# define __BUILTINBC(ret,name,params) ret __builtin_##name params __RENAME("__bound_"#name);
# define __BOUND(ret,name,params) ret name params __RENAME("__bound_"#name);
#else
# define __BUILTINBC(ret,name,params) ret __builtin_##name params __RENAME(#name);
# define __BOUND(ret,name,params)
#endif
#ifdef _WIN32
#define __BOTH __BOUND
#define __BUILTIN(ret,name,params)
#else
#define __BOTH(ret,name,params) __BUILTINBC(ret,name,params)__BOUND(ret,name,params)
#define __BUILTIN(ret,name,params) ret __builtin_##name params __RENAME(#name);
#endif
__BOTH(void*, memcpy, (void *, const void*, __SIZE_TYPE__))
__BOTH(void*, memmove, (void *, const void*, __SIZE_TYPE__))
__BOTH(void*, memset, (void *, int, __SIZE_TYPE__))
__BOTH(int, memcmp, (const void *, const void*, __SIZE_TYPE__))
__BOTH(__SIZE_TYPE__, strlen, (const char *))
__BOTH(char*, strcpy, (char *, const char *))
__BOTH(char*, strncpy, (char *, const char*, __SIZE_TYPE__))
__BOTH(int, strcmp, (const char*, const char*))
__BOTH(int, strncmp, (const char*, const char*, __SIZE_TYPE__))
__BOTH(char*, strcat, (char*, const char*))
__BOTH(char*, strncat, (char*, const char*, __SIZE_TYPE__))
__BOTH(char*, strchr, (const char*, int))
__BOTH(char*, strrchr, (const char*, int))
__BOTH(char*, strdup, (const char*))
#if defined __ARM_EABI__
__BOUND(void*,__aeabi_memcpy,(void*,const void*,__SIZE_TYPE__))
__BOUND(void*,__aeabi_memmove,(void*,const void*,__SIZE_TYPE__))
__BOUND(void*,__aeabi_memmove4,(void*,const void*,__SIZE_TYPE__))
__BOUND(void*,__aeabi_memmove8,(void*,const void*,__SIZE_TYPE__))
__BOUND(void*,__aeabi_memset,(void*,int,__SIZE_TYPE__))
#endif
#if defined __linux__ || defined __APPLE__ // HAVE MALLOC_REDIR
#define __MAYBE_REDIR __BUILTIN
#else
#define __MAYBE_REDIR __BOTH
#endif
__MAYBE_REDIR(void*, malloc, (__SIZE_TYPE__))
__MAYBE_REDIR(void*, realloc, (void *, __SIZE_TYPE__))
__MAYBE_REDIR(void*, calloc, (__SIZE_TYPE__, __SIZE_TYPE__))
__MAYBE_REDIR(void*, memalign, (__SIZE_TYPE__, __SIZE_TYPE__))
__MAYBE_REDIR(void, free, (void*))
__BOTH(void*, alloca, (__SIZE_TYPE__))
void *alloca(__SIZE_TYPE__);
__BUILTIN(void, abort, (void))
__BOUND(void, longjmp, ())
#if !defined _WIN32
__BOUND(void*, mmap, ())
__BOUND(int, munmap, ())
#endif
#undef __BUILTINBC
#undef __BUILTIN
#undef __BOUND
#undef __BOTH
#undef __MAYBE_REDIR
#undef __RENAME
#define __BUILTIN_EXTERN(name,u) \
int __builtin_##name(u int); \
int __builtin_##name##l(u long); \
int __builtin_##name##ll(u long long);
__BUILTIN_EXTERN(ffs,)
__BUILTIN_EXTERN(clz, unsigned)
__BUILTIN_EXTERN(ctz, unsigned)
__BUILTIN_EXTERN(clrsb,)
__BUILTIN_EXTERN(popcount, unsigned)
__BUILTIN_EXTERN(parity, unsigned)
#undef __BUILTIN_EXTERN
#endif /* ndef __TCC_PP__ */
+89
View File
@@ -0,0 +1,89 @@
/*
* ISO C Standard: 7.22 Type-generic math <tgmath.h>
*/
#ifndef _TGMATH_H
#define _TGMATH_H
#include <math.h>
#ifndef __cplusplus
#define __tgmath_real(x, F) \
_Generic ((x), float: F##f, long double: F##l, default: F)(x)
#define __tgmath_real_2_1(x, y, F) \
_Generic ((x), float: F##f, long double: F##l, default: F)(x, y)
#define __tgmath_real_2(x, y, F) \
_Generic ((x)+(y), float: F##f, long double: F##l, default: F)(x, y)
#define __tgmath_real_3_2(x, y, z, F) \
_Generic ((x)+(y), float: F##f, long double: F##l, default: F)(x, y, z)
#define __tgmath_real_3(x, y, z, F) \
_Generic ((x)+(y)+(z), float: F##f, long double: F##l, default: F)(x, y, z)
/* Functions defined in both <math.h> and <complex.h> (7.22p4) */
#define acos(z) __tgmath_real(z, acos)
#define asin(z) __tgmath_real(z, asin)
#define atan(z) __tgmath_real(z, atan)
#define acosh(z) __tgmath_real(z, acosh)
#define asinh(z) __tgmath_real(z, asinh)
#define atanh(z) __tgmath_real(z, atanh)
#define cos(z) __tgmath_real(z, cos)
#define sin(z) __tgmath_real(z, sin)
#define tan(z) __tgmath_real(z, tan)
#define cosh(z) __tgmath_real(z, cosh)
#define sinh(z) __tgmath_real(z, sinh)
#define tanh(z) __tgmath_real(z, tanh)
#define exp(z) __tgmath_real(z, exp)
#define log(z) __tgmath_real(z, log)
#define pow(z1,z2) __tgmath_real_2(z1, z2, pow)
#define sqrt(z) __tgmath_real(z, sqrt)
#define fabs(z) __tgmath_real(z, fabs)
/* Functions defined in <math.h> only (7.22p5) */
#define atan2(x,y) __tgmath_real_2(x, y, atan2)
#define cbrt(x) __tgmath_real(x, cbrt)
#define ceil(x) __tgmath_real(x, ceil)
#define copysign(x,y) __tgmath_real_2(x, y, copysign)
#define erf(x) __tgmath_real(x, erf)
#define erfc(x) __tgmath_real(x, erfc)
#define exp2(x) __tgmath_real(x, exp2)
#define expm1(x) __tgmath_real(x, expm1)
#define fdim(x,y) __tgmath_real_2(x, y, fdim)
#define floor(x) __tgmath_real(x, floor)
#define fma(x,y,z) __tgmath_real_3(x, y, z, fma)
#define fmax(x,y) __tgmath_real_2(x, y, fmax)
#define fmin(x,y) __tgmath_real_2(x, y, fmin)
#define fmod(x,y) __tgmath_real_2(x, y, fmod)
#define frexp(x,y) __tgmath_real_2_1(x, y, frexp)
#define hypot(x,y) __tgmath_real_2(x, y, hypot)
#define ilogb(x) __tgmath_real(x, ilogb)
#define ldexp(x,y) __tgmath_real_2_1(x, y, ldexp)
#define lgamma(x) __tgmath_real(x, lgamma)
#define llrint(x) __tgmath_real(x, llrint)
#define llround(x) __tgmath_real(x, llround)
#define log10(x) __tgmath_real(x, log10)
#define log1p(x) __tgmath_real(x, log1p)
#define log2(x) __tgmath_real(x, log2)
#define logb(x) __tgmath_real(x, logb)
#define lrint(x) __tgmath_real(x, lrint)
#define lround(x) __tgmath_real(x, lround)
#define nearbyint(x) __tgmath_real(x, nearbyint)
#define nextafter(x,y) __tgmath_real_2(x, y, nextafter)
#define nexttoward(x,y) __tgmath_real_2(x, y, nexttoward)
#define remainder(x,y) __tgmath_real_2(x, y, remainder)
#define remquo(x,y,z) __tgmath_real_3_2(x, y, z, remquo)
#define rint(x) __tgmath_real(x, rint)
#define round(x) __tgmath_real(x, round)
#define scalbln(x,y) __tgmath_real_2_1(x, y, scalbln)
#define scalbn(x,y) __tgmath_real_2_1(x, y, scalbn)
#define tgamma(x) __tgmath_real(x, tgamma)
#define trunc(x) __tgmath_real(x, trunc)
/* Functions defined in <complex.h> only (7.22p6)
#define carg(z) __tgmath_cplx_only(z, carg)
#define cimag(z) __tgmath_cplx_only(z, cimag)
#define conj(z) __tgmath_cplx_only(z, conj)
#define cproj(z) __tgmath_cplx_only(z, cproj)
#define creal(z) __tgmath_cplx_only(z, creal)
*/
#endif /* __cplusplus */
#endif /* _TGMATH_H */
+12
View File
@@ -0,0 +1,12 @@
/**
* This file has no copyright assigned and is placed in the Public Domain.
* This file is part of the w64 mingw-runtime package.
* No warranty is given; refer to the file DISCLAIMER within this package.
*/
#ifndef _VARARGS_H
#define _VARARGS_H
#error "TinyCC no longer implements <varargs.h>."
#error "Revise your code to use <stdarg.h>."
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+80
View File
@@ -0,0 +1,80 @@
/* Simple libc header for TCC
*
* Add any function you want from the libc there. This file is here
* only for your convenience so that you do not need to put the whole
* glibc include files on your floppy disk
*/
#ifndef _TCCLIB_H
#define _TCCLIB_H
#include <stddef.h>
#include <stdarg.h>
/* stdlib.h */
void *calloc(size_t nmemb, size_t size);
void *malloc(size_t size);
void free(void *ptr);
void *realloc(void *ptr, size_t size);
int atoi(const char *nptr);
long int strtol(const char *nptr, char **endptr, int base);
unsigned long int strtoul(const char *nptr, char **endptr, int base);
void exit(int);
/* stdio.h */
typedef struct __FILE FILE;
#define EOF (-1)
extern FILE *stdin;
extern FILE *stdout;
extern FILE *stderr;
FILE *fopen(const char *path, const char *mode);
FILE *fdopen(int fildes, const char *mode);
FILE *freopen(const char *path, const char *mode, FILE *stream);
int fclose(FILE *stream);
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream);
int fgetc(FILE *stream);
char *fgets(char *s, int size, FILE *stream);
int getc(FILE *stream);
int getchar(void);
char *gets(char *s);
int ungetc(int c, FILE *stream);
int fflush(FILE *stream);
int putchar (int c);
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
int asprintf(char **strp, const char *format, ...);
int dprintf(int fd, const char *format, ...);
int vprintf(const char *format, va_list ap);
int vfprintf(FILE *stream, const char *format, va_list ap);
int vsprintf(char *str, const char *format, va_list ap);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
int vasprintf(char **strp, const char *format, va_list ap);
int vdprintf(int fd, const char *format, va_list ap);
void perror(const char *s);
/* string.h */
char *strcat(char *dest, const char *src);
char *strchr(const char *s, int c);
char *strrchr(const char *s, int c);
char *strcpy(char *dest, const char *src);
void *memcpy(void *dest, const void *src, size_t n);
void *memmove(void *dest, const void *src, size_t n);
void *memset(void *s, int c, size_t n);
char *strdup(const char *s);
size_t strlen(const char *s);
/* dlfcn.h */
#define RTLD_LAZY 0x001
#define RTLD_NOW 0x002
#define RTLD_GLOBAL 0x100
void *dlopen(const char *filename, int flag);
const char *dlerror(void);
void *dlsym(void *handle, char *symbol);
int dlclose(void *handle);
#endif /* _TCCLIB_H */
File diff suppressed because it is too large Load Diff
+430
View File
@@ -0,0 +1,430 @@
/*********************************************************************/
/* keywords */
DEF(TOK_IF, "if")
DEF(TOK_ELSE, "else")
DEF(TOK_WHILE, "while")
DEF(TOK_FOR, "for")
DEF(TOK_DO, "do")
DEF(TOK_CONTINUE, "continue")
DEF(TOK_BREAK, "break")
DEF(TOK_RETURN, "return")
DEF(TOK_GOTO, "goto")
DEF(TOK_SWITCH, "switch")
DEF(TOK_CASE, "case")
DEF(TOK_DEFAULT, "default")
DEF(TOK_ASM1, "asm")
DEF(TOK_ASM2, "__asm")
DEF(TOK_ASM3, "__asm__")
DEF(TOK_EXTERN, "extern")
DEF(TOK_STATIC, "static")
DEF(TOK_UNSIGNED, "unsigned")
DEF(TOK__Atomic, "_Atomic")
DEF(TOK_CONST1, "const")
DEF(TOK_CONST2, "__const") /* gcc keyword */
DEF(TOK_CONST3, "__const__") /* gcc keyword */
DEF(TOK_VOLATILE1, "volatile")
DEF(TOK_VOLATILE2, "__volatile") /* gcc keyword */
DEF(TOK_VOLATILE3, "__volatile__") /* gcc keyword */
DEF(TOK_REGISTER, "register")
DEF(TOK_SIGNED1, "signed")
DEF(TOK_SIGNED2, "__signed") /* gcc keyword */
DEF(TOK_SIGNED3, "__signed__") /* gcc keyword */
DEF(TOK_AUTO, "auto")
DEF(TOK_INLINE1, "inline")
DEF(TOK_INLINE2, "__inline") /* gcc keyword */
DEF(TOK_INLINE3, "__inline__") /* gcc keyword */
DEF(TOK_RESTRICT1, "restrict")
DEF(TOK_RESTRICT2, "__restrict")
DEF(TOK_RESTRICT3, "__restrict__")
DEF(TOK_EXTENSION, "__extension__") /* gcc keyword */
DEF(TOK_THREAD_LOCAL, "_Thread_local") /* C11 thread-local storage */
DEF(TOK_GENERIC, "_Generic")
DEF(TOK_STATIC_ASSERT, "_Static_assert")
DEF(TOK_VOID, "void")
DEF(TOK_CHAR, "char")
DEF(TOK_INT, "int")
DEF(TOK_FLOAT, "float")
DEF(TOK_DOUBLE, "double")
DEF(TOK_BOOL, "_Bool")
DEF(TOK_COMPLEX, "_Complex")
DEF(TOK_SHORT, "short")
DEF(TOK_LONG, "long")
DEF(TOK_STRUCT, "struct")
DEF(TOK_UNION, "union")
DEF(TOK_TYPEDEF, "typedef")
DEF(TOK_ENUM, "enum")
DEF(TOK_SIZEOF, "sizeof")
DEF(TOK_ATTRIBUTE1, "__attribute")
DEF(TOK_ATTRIBUTE2, "__attribute__")
DEF(TOK_ALIGNOF1, "__alignof")
DEF(TOK_ALIGNOF2, "__alignof__")
DEF(TOK_ALIGNOF3, "_Alignof")
DEF(TOK_ALIGNAS, "_Alignas")
DEF(TOK_TYPEOF1, "typeof")
DEF(TOK_TYPEOF2, "__typeof")
DEF(TOK_TYPEOF3, "__typeof__")
DEF(TOK_LABEL, "__label__")
/*********************************************************************/
/* the following are not keywords. They are included to ease parsing */
/* preprocessor only */
DEF(TOK_DEFINE, "define")
DEF(TOK_INCLUDE, "include")
DEF(TOK_INCLUDE_NEXT, "include_next")
DEF(TOK_IFDEF, "ifdef")
DEF(TOK_IFNDEF, "ifndef")
DEF(TOK_ELIF, "elif")
DEF(TOK_ENDIF, "endif")
DEF(TOK_DEFINED, "defined")
DEF(TOK_UNDEF, "undef")
DEF(TOK_ERROR, "error")
DEF(TOK_WARNING, "warning")
DEF(TOK_LINE, "line")
DEF(TOK_PRAGMA, "pragma")
DEF(TOK___LINE__, "__LINE__")
DEF(TOK___FILE__, "__FILE__")
DEF(TOK___DATE__, "__DATE__")
DEF(TOK___TIME__, "__TIME__")
DEF(TOK___FUNCTION__, "__FUNCTION__")
DEF(TOK___VA_ARGS__, "__VA_ARGS__")
DEF(TOK___COUNTER__, "__COUNTER__")
DEF(TOK___HAS_INCLUDE, "__has_include")
DEF(TOK___HAS_INCLUDE_NEXT, "__has_include_next")
/* special identifiers */
DEF(TOK___FUNC__, "__func__")
/* special floating point values */
DEF(TOK___NAN__, "__nan__")
DEF(TOK___SNAN__, "__snan__")
DEF(TOK___INF__, "__inf__")
/* attribute identifiers */
/* XXX: handle all tokens generically since speed is not critical */
DEF(TOK_SECTION1, "section")
DEF(TOK_SECTION2, "__section__")
DEF(TOK_ALIGNED1, "aligned")
DEF(TOK_ALIGNED2, "__aligned__")
DEF(TOK_PACKED1, "packed")
DEF(TOK_PACKED2, "__packed__")
DEF(TOK_WEAK1, "weak")
DEF(TOK_WEAK2, "__weak__")
DEF(TOK_ALIAS1, "alias")
DEF(TOK_ALIAS2, "__alias__")
DEF(TOK_USED1, "used")
DEF(TOK_USED2, "__used__")
DEF(TOK_UNUSED1, "unused")
DEF(TOK_UNUSED2, "__unused__")
DEF(TOK_FORMAT1, "format")
DEF(TOK_FORMAT2, "__format__")
DEF(TOK_NODEBUG1, "nodebug")
DEF(TOK_NODEBUG2, "__nodebug__")
DEF(TOK_CDECL1, "cdecl")
DEF(TOK_CDECL2, "__cdecl")
DEF(TOK_CDECL3, "__cdecl__")
DEF(TOK_STDCALL1, "stdcall")
DEF(TOK_STDCALL2, "__stdcall")
DEF(TOK_STDCALL3, "__stdcall__")
DEF(TOK_FASTCALL1, "fastcall")
DEF(TOK_FASTCALL2, "__fastcall")
DEF(TOK_FASTCALL3, "__fastcall__")
DEF(TOK_THISCALL1, "thiscall")
DEF(TOK_THISCALL2, "__thiscall")
DEF(TOK_THISCALL3, "__thiscall__")
DEF(TOK_REGPARM1, "regparm")
DEF(TOK_REGPARM2, "__regparm__")
DEF(TOK_CLEANUP1, "cleanup")
DEF(TOK_CLEANUP2, "__cleanup__")
DEF(TOK_CONSTRUCTOR1, "constructor")
DEF(TOK_CONSTRUCTOR2, "__constructor__")
DEF(TOK_DESTRUCTOR1, "destructor")
DEF(TOK_DESTRUCTOR2, "__destructor__")
DEF(TOK_ALWAYS_INLINE1, "always_inline")
DEF(TOK_ALWAYS_INLINE2, "__always_inline__")
DEF(TOK_NOINLINE, "__noinline__")
DEF(TOK_PURE1, "pure")
DEF(TOK_PURE2, "__pure__")
DEF(TOK_MODE, "__mode__")
DEF(TOK_MODE_QI, "__QI__")
DEF(TOK_MODE_DI, "__DI__")
DEF(TOK_MODE_HI, "__HI__")
DEF(TOK_MODE_SI, "__SI__")
DEF(TOK_MODE_word, "__word__")
DEF(TOK_DLLEXPORT, "dllexport")
DEF(TOK_DLLIMPORT, "dllimport")
DEF(TOK_NODECORATE, "nodecorate")
DEF(TOK_NORETURN1, "noreturn")
DEF(TOK_NORETURN2, "__noreturn__")
DEF(TOK_NORETURN3, "_Noreturn")
DEF(TOK_VISIBILITY1, "visibility")
DEF(TOK_VISIBILITY2, "__visibility__")
DEF(TOK_builtin_types_compatible_p, "__builtin_types_compatible_p")
DEF(TOK_builtin_choose_expr, "__builtin_choose_expr")
DEF(TOK_builtin_constant_p, "__builtin_constant_p")
DEF(TOK_builtin_frame_address, "__builtin_frame_address")
DEF(TOK_builtin_return_address, "__builtin_return_address")
DEF(TOK_builtin_expect, "__builtin_expect")
DEF(TOK_builtin_unreachable, "__builtin_unreachable")
/*DEF(TOK_builtin_va_list, "__builtin_va_list")*/
#if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64
DEF(TOK_builtin_va_start, "__builtin_va_start")
#elif defined TCC_TARGET_X86_64
DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types")
#elif defined TCC_TARGET_ARM64
DEF(TOK_builtin_va_start, "__builtin_va_start")
DEF(TOK_builtin_va_arg, "__builtin_va_arg")
#elif defined TCC_TARGET_RISCV64
DEF(TOK_builtin_va_start, "__builtin_va_start")
#endif
/* atomic operations */
#define DEF_ATOMIC(ID) DEF(TOK_##__##ID, "__"#ID)
DEF_ATOMIC(atomic_store)
DEF_ATOMIC(atomic_load)
DEF_ATOMIC(atomic_exchange)
DEF_ATOMIC(atomic_compare_exchange)
DEF_ATOMIC(atomic_fetch_add)
DEF_ATOMIC(atomic_fetch_sub)
DEF_ATOMIC(atomic_fetch_or)
DEF_ATOMIC(atomic_fetch_xor)
DEF_ATOMIC(atomic_fetch_and)
DEF_ATOMIC(atomic_fetch_nand)
DEF_ATOMIC(atomic_add_fetch)
DEF_ATOMIC(atomic_sub_fetch)
DEF_ATOMIC(atomic_or_fetch)
DEF_ATOMIC(atomic_xor_fetch)
DEF_ATOMIC(atomic_and_fetch)
DEF_ATOMIC(atomic_nand_fetch)
/* pragma */
DEF(TOK_pack, "pack")
#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64) && \
!defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_ARM64) && \
!defined(TCC_TARGET_RISCV64)
/* already defined for assembler */
DEF(TOK_ASM_push, "push")
DEF(TOK_ASM_pop, "pop")
#endif
DEF(TOK_comment, "comment")
DEF(TOK_lib, "lib")
DEF(TOK_push_macro, "push_macro")
DEF(TOK_pop_macro, "pop_macro")
DEF(TOK_once, "once")
DEF(TOK_option, "option")
/* builtin functions or variables */
#ifndef TCC_ARM_EABI
DEF(TOK_memcpy, "memcpy")
DEF(TOK_memmove, "memmove")
DEF(TOK_memset, "memset")
DEF(TOK___divdi3, "__divdi3")
DEF(TOK___moddi3, "__moddi3")
DEF(TOK___udivdi3, "__udivdi3")
DEF(TOK___umoddi3, "__umoddi3")
DEF(TOK___ashrdi3, "__ashrdi3")
DEF(TOK___lshrdi3, "__lshrdi3")
DEF(TOK___ashldi3, "__ashldi3")
DEF(TOK___floatundisf, "__floatundisf")
DEF(TOK___floatundidf, "__floatundidf")
# ifndef TCC_ARM_VFP
DEF(TOK___floatundixf, "__floatundixf")
DEF(TOK___fixunsxfdi, "__fixunsxfdi")
# endif
DEF(TOK___fixunssfdi, "__fixunssfdi")
DEF(TOK___fixunsdfdi, "__fixunsdfdi")
#endif
#if defined TCC_TARGET_ARM
# ifdef TCC_ARM_EABI
DEF(TOK_memcpy, "__aeabi_memcpy")
DEF(TOK_memmove, "__aeabi_memmove")
DEF(TOK_memmove4, "__aeabi_memmove4")
DEF(TOK_memmove8, "__aeabi_memmove8")
DEF(TOK_memset, "__aeabi_memset")
DEF(TOK___aeabi_ldivmod, "__aeabi_ldivmod")
DEF(TOK___aeabi_uldivmod, "__aeabi_uldivmod")
DEF(TOK___aeabi_idivmod, "__aeabi_idivmod")
DEF(TOK___aeabi_uidivmod, "__aeabi_uidivmod")
DEF(TOK___divsi3, "__aeabi_idiv")
DEF(TOK___udivsi3, "__aeabi_uidiv")
DEF(TOK___floatdisf, "__aeabi_l2f")
DEF(TOK___floatdidf, "__aeabi_l2d")
DEF(TOK___fixsfdi, "__aeabi_f2lz")
DEF(TOK___fixdfdi, "__aeabi_d2lz")
DEF(TOK___ashrdi3, "__aeabi_lasr")
DEF(TOK___lshrdi3, "__aeabi_llsr")
DEF(TOK___ashldi3, "__aeabi_llsl")
DEF(TOK___floatundisf, "__aeabi_ul2f")
DEF(TOK___floatundidf, "__aeabi_ul2d")
DEF(TOK___fixunssfdi, "__aeabi_f2ulz")
DEF(TOK___fixunsdfdi, "__aeabi_d2ulz")
# else
DEF(TOK___modsi3, "__modsi3")
DEF(TOK___umodsi3, "__umodsi3")
DEF(TOK___divsi3, "__divsi3")
DEF(TOK___udivsi3, "__udivsi3")
DEF(TOK___floatdisf, "__floatdisf")
DEF(TOK___floatdidf, "__floatdidf")
# ifndef TCC_ARM_VFP
DEF(TOK___floatdixf, "__floatdixf")
DEF(TOK___fixunssfsi, "__fixunssfsi")
DEF(TOK___fixunsdfsi, "__fixunsdfsi")
DEF(TOK___fixunsxfsi, "__fixunsxfsi")
DEF(TOK___fixxfdi, "__fixxfdi")
# endif
DEF(TOK___fixsfdi, "__fixsfdi")
DEF(TOK___fixdfdi, "__fixdfdi")
# endif
#endif
#if defined TCC_TARGET_C67
DEF(TOK__divi, "_divi")
DEF(TOK__divu, "_divu")
DEF(TOK__divf, "_divf")
DEF(TOK__divd, "_divd")
DEF(TOK__remi, "_remi")
DEF(TOK__remu, "_remu")
#endif
#if defined TCC_TARGET_I386
DEF(TOK___fixsfdi, "__fixsfdi")
DEF(TOK___fixdfdi, "__fixdfdi")
DEF(TOK___fixxfdi, "__fixxfdi")
#endif
#if defined TCC_TARGET_X86_64
DEF(TOK___fixxfdi, "__fixxfdi")
#endif
DEF(TOK_alloca, "alloca")
#if defined TCC_TARGET_PE
DEF(TOK___chkstk, "__chkstk")
#endif
#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64
DEF(TOK___arm64_clear_cache, "__arm64_clear_cache")
DEF(TOK___addtf3, "__addtf3")
DEF(TOK___subtf3, "__subtf3")
DEF(TOK___multf3, "__multf3")
DEF(TOK___divtf3, "__divtf3")
DEF(TOK___extendsftf2, "__extendsftf2")
DEF(TOK___extenddftf2, "__extenddftf2")
DEF(TOK___trunctfsf2, "__trunctfsf2")
DEF(TOK___trunctfdf2, "__trunctfdf2")
DEF(TOK___negtf2, "__negtf2")
DEF(TOK___fixtfsi, "__fixtfsi")
DEF(TOK___fixtfdi, "__fixtfdi")
DEF(TOK___fixunstfsi, "__fixunstfsi")
DEF(TOK___fixunstfdi, "__fixunstfdi")
DEF(TOK___floatsitf, "__floatsitf")
DEF(TOK___floatditf, "__floatditf")
DEF(TOK___floatunsitf, "__floatunsitf")
DEF(TOK___floatunditf, "__floatunditf")
DEF(TOK___eqtf2, "__eqtf2")
DEF(TOK___netf2, "__netf2")
DEF(TOK___lttf2, "__lttf2")
DEF(TOK___letf2, "__letf2")
DEF(TOK___gttf2, "__gttf2")
DEF(TOK___getf2, "__getf2")
#endif
/* bound checking symbols */
#ifdef CONFIG_TCC_BCHECK
DEF(TOK___bound_ptr_add, "__bound_ptr_add")
DEF(TOK___bound_ptr_indir1, "__bound_ptr_indir1")
DEF(TOK___bound_ptr_indir2, "__bound_ptr_indir2")
DEF(TOK___bound_ptr_indir4, "__bound_ptr_indir4")
DEF(TOK___bound_ptr_indir8, "__bound_ptr_indir8")
DEF(TOK___bound_ptr_indir12, "__bound_ptr_indir12")
DEF(TOK___bound_ptr_indir16, "__bound_ptr_indir16")
DEF(TOK___bound_main_arg, "__bound_main_arg")
DEF(TOK___bound_local_new, "__bound_local_new")
DEF(TOK___bound_local_delete, "__bound_local_delete")
DEF(TOK___bound_setjmp, "__bound_setjmp")
DEF(TOK___bound_longjmp, "__bound_longjmp")
DEF(TOK___bound_new_region, "__bound_new_region")
# ifdef TCC_TARGET_PE
# ifdef TCC_TARGET_X86_64
DEF(TOK___bound_alloca_nr, "__bound_alloca_nr")
# endif
# else
DEF(TOK_sigsetjmp, "sigsetjmp")
DEF(TOK___sigsetjmp, "__sigsetjmp")
DEF(TOK_siglongjmp, "siglongjmp")
# endif
DEF(TOK_setjmp, "setjmp")
DEF(TOK__setjmp, "_setjmp")
DEF(TOK_longjmp, "longjmp")
#endif
/*********************************************************************/
/* Tiny Assembler */
#define DEF_ASM(x) DEF(TOK_ASM_ ## x, #x)
#define DEF_ASMDIR(x) DEF(TOK_ASMDIR_ ## x, "." #x)
#define TOK_ASM_int TOK_INT
#define TOK_ASMDIR_FIRST TOK_ASMDIR_byte
#define TOK_ASMDIR_LAST TOK_ASMDIR_section
DEF_ASMDIR(byte) /* must be first directive */
DEF_ASMDIR(word)
DEF_ASMDIR(align)
DEF_ASMDIR(balign)
DEF_ASMDIR(p2align)
DEF_ASMDIR(set)
DEF_ASMDIR(skip)
DEF_ASMDIR(space)
DEF_ASMDIR(string)
DEF_ASMDIR(asciz)
DEF_ASMDIR(ascii)
DEF_ASMDIR(file)
DEF_ASMDIR(globl)
DEF_ASMDIR(global)
DEF_ASMDIR(weak)
DEF_ASMDIR(hidden)
DEF_ASMDIR(ident)
DEF_ASMDIR(size)
DEF_ASMDIR(type)
DEF_ASMDIR(text)
DEF_ASMDIR(data)
DEF_ASMDIR(bss)
DEF_ASMDIR(previous)
DEF_ASMDIR(pushsection)
DEF_ASMDIR(popsection)
DEF_ASMDIR(fill)
DEF_ASMDIR(rept)
DEF_ASMDIR(endr)
DEF_ASMDIR(org)
DEF_ASMDIR(quad)
#if defined(TCC_TARGET_I386)
DEF_ASMDIR(code16)
DEF_ASMDIR(code32)
#elif defined(TCC_TARGET_X86_64)
DEF_ASMDIR(code64)
#elif defined(TCC_TARGET_RISCV64)
DEF_ASMDIR(option)
#endif
DEF_ASMDIR(short)
DEF_ASMDIR(long)
DEF_ASMDIR(int)
DEF_ASMDIR(symver)
DEF_ASMDIR(reloc)
DEF_ASMDIR(section) /* must be last directive */
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
#include "i386-tok.h"
#endif
#if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64
#include "arm-tok.h"
#endif
#if defined TCC_TARGET_RISCV64
#include "riscv64-tok.h"
#endif
+651
View File
@@ -0,0 +1,651 @@
/* -------------------------------------------------------------- */
/*
* TCC - Tiny C Compiler
*
* tcctools.c - extra tools and and -m32/64 support
*
*/
/* -------------------------------------------------------------- */
/*
* This program is for making libtcc1.a without ar
* tiny_libmaker - tiny elf lib maker
* usage: tiny_libmaker [lib] files...
* Copyright (c) 2007 Timppa
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "tcc.h"
//#define ARMAG "!<arch>\n"
#define ARFMAG "`\n"
typedef struct {
char ar_name[16];
char ar_date[12];
char ar_uid[6];
char ar_gid[6];
char ar_mode[8];
char ar_size[10];
char ar_fmag[2];
} ArHdr;
static unsigned long le2belong(unsigned long ul) {
return ((ul & 0xFF0000)>>8)+((ul & 0xFF000000)>>24) +
((ul & 0xFF)<<24)+((ul & 0xFF00)<<8);
}
static int ar_usage(int ret) {
fprintf(stderr, "usage: tcc -ar [crstvx] lib [files]\n");
fprintf(stderr, "create library ([abdiopN] not supported).\n");
return ret;
}
ST_FUNC int tcc_tool_ar(int argc, char **argv)
{
static const ArHdr arhdr_init = {
"/ ",
"0 ",
"0 ",
"0 ",
"0 ",
"0 ",
ARFMAG
};
ArHdr arhdr = arhdr_init;
ArHdr arhdro = arhdr_init;
FILE *fi, *fh = NULL, *fo = NULL;
const char *created_file = NULL; // must delete on error
ElfW(Ehdr) *ehdr;
ElfW(Shdr) *shdr;
ElfW(Sym) *sym;
int i, fsize, i_lib, i_obj;
char *buf, *shstr, *symtab, *strtab;
int symtabsize = 0;//, strtabsize = 0;
char *anames = NULL;
int *afpos = NULL;
int istrlen, strpos = 0, fpos = 0, funccnt = 0, funcmax, hofs;
char tfile[260], stmp[20];
char *file, *name;
int ret = 2;
const char *ops_conflict = "habdiopN"; // unsupported but destructive if ignored.
int extract = 0;
int table = 0;
int verbose = 0;
i_lib = 0; i_obj = 0; // will hold the index of the lib and first obj
for (i = 1; i < argc; i++) {
const char *a = argv[i];
if (*a == '-' && strchr(a, '.'))
ret = 1; // -x.y is always invalid (same as gnu ar)
if ((*a == '-') || (i == 1 && !strchr(a, '.'))) { // options argument
if (strpbrk(a, ops_conflict))
ret = 1;
if (strchr(a, 'x'))
extract = 1;
if (strchr(a, 't'))
table = 1;
if (strchr(a, 'v'))
verbose = 1;
} else { // lib or obj files: don't abort - keep validating all args.
if (!i_lib) // first file is the lib
i_lib = i;
else if (!i_obj) // second file is the first obj
i_obj = i;
}
}
if (!i_lib) // i_obj implies also i_lib.
ret = 1;
i_obj = i_obj ? i_obj : argc; // An empty archive will be generated if no input file is given
if (ret == 1)
return ar_usage(ret);
if (extract || table) {
if ((fh = fopen(argv[i_lib], "rb")) == NULL)
{
fprintf(stderr, "tcc: ar: can't open file %s\n", argv[i_lib]);
goto finish;
}
fread(stmp, 1, 8, fh);
if (memcmp(stmp,ARMAG,8))
{
no_ar:
fprintf(stderr, "tcc: ar: not an ar archive %s\n", argv[i_lib]);
goto finish;
}
while (fread(&arhdr, 1, sizeof(arhdr), fh) == sizeof(arhdr)) {
char *p, *e;
if (memcmp(arhdr.ar_fmag, ARFMAG, 2))
goto no_ar;
p = arhdr.ar_name;
for (e = p + sizeof arhdr.ar_name; e > p && e[-1] == ' ';)
e--;
*e = '\0';
arhdr.ar_size[sizeof arhdr.ar_size-1] = 0;
fsize = atoi(arhdr.ar_size);
buf = tcc_malloc(fsize + 1);
fread(buf, fsize, 1, fh);
if (strcmp(arhdr.ar_name,"/") && strcmp(arhdr.ar_name,"/SYM64/")) {
if (e > p && e[-1] == '/')
e[-1] = '\0';
/* tv not implemented */
if (table || verbose)
printf("%s%s\n", extract ? "x - " : "", arhdr.ar_name);
if (extract) {
if ((fo = fopen(arhdr.ar_name, "wb")) == NULL)
{
fprintf(stderr, "tcc: ar: can't create file %s\n",
arhdr.ar_name);
tcc_free(buf);
goto finish;
}
fwrite(buf, fsize, 1, fo);
fclose(fo);
/* ignore date/uid/gid/mode */
}
}
if (fsize & 1)
fgetc(fh);
tcc_free(buf);
}
ret = 0;
finish:
if (fh)
fclose(fh);
return ret;
}
if ((fh = fopen(argv[i_lib], "wb")) == NULL)
{
fprintf(stderr, "tcc: ar: can't create file %s\n", argv[i_lib]);
goto the_end;
}
created_file = argv[i_lib];
sprintf(tfile, "%s.tmp", argv[i_lib]);
if ((fo = fopen(tfile, "wb+")) == NULL)
{
fprintf(stderr, "tcc: ar: can't create temporary file %s\n", tfile);
goto the_end;
}
funcmax = 250;
afpos = tcc_realloc(NULL, funcmax * sizeof *afpos); // 250 func
memcpy(&arhdro.ar_mode, "100644", 6);
// i_obj = first input object file
while (i_obj < argc)
{
if (*argv[i_obj] == '-') { // by now, all options start with '-'
i_obj++;
continue;
}
if ((fi = fopen(argv[i_obj], "rb")) == NULL) {
fprintf(stderr, "tcc: ar: can't open file %s \n", argv[i_obj]);
goto the_end;
}
if (verbose)
printf("a - %s\n", argv[i_obj]);
fseek(fi, 0, SEEK_END);
fsize = ftell(fi);
fseek(fi, 0, SEEK_SET);
buf = tcc_malloc(fsize + 1);
fread(buf, fsize, 1, fi);
fclose(fi);
// elf header
ehdr = (ElfW(Ehdr) *)buf;
if (ehdr->e_ident[4] != ELFCLASSW)
{
fprintf(stderr, "tcc: ar: Unsupported Elf Class: %s\n", argv[i_obj]);
goto the_end;
}
shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + ehdr->e_shstrndx * ehdr->e_shentsize);
shstr = (char *)(buf + shdr->sh_offset);
symtab = strtab = NULL;
for (i = 0; i < ehdr->e_shnum; i++)
{
shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + i * ehdr->e_shentsize);
if (!shdr->sh_offset)
continue;
if (shdr->sh_type == SHT_SYMTAB)
{
symtab = (char *)(buf + shdr->sh_offset);
symtabsize = shdr->sh_size;
}
if (shdr->sh_type == SHT_STRTAB)
{
if (!strcmp(shstr + shdr->sh_name, ".strtab"))
{
strtab = (char *)(buf + shdr->sh_offset);
//strtabsize = shdr->sh_size;
}
}
}
if (symtab && strtab)
{
int nsym = symtabsize / sizeof(ElfW(Sym));
//printf("symtab: info size shndx name\n");
for (i = 1; i < nsym; i++)
{
sym = (ElfW(Sym) *) (symtab + i * sizeof(ElfW(Sym)));
if (sym->st_shndx &&
(sym->st_info == 0x10
|| sym->st_info == 0x11
|| sym->st_info == 0x12
|| sym->st_info == 0x20
|| sym->st_info == 0x21
|| sym->st_info == 0x22
)) {
//printf("symtab: %2Xh %4Xh %2Xh %s\n", sym->st_info, sym->st_size, sym->st_shndx, strtab + sym->st_name);
istrlen = strlen(strtab + sym->st_name)+1;
anames = tcc_realloc(anames, strpos+istrlen);
strcpy(anames + strpos, strtab + sym->st_name);
strpos += istrlen;
if (++funccnt >= funcmax) {
funcmax += 250;
afpos = tcc_realloc(afpos, funcmax * sizeof *afpos); // 250 func more
}
afpos[funccnt] = fpos;
}
}
}
file = argv[i_obj];
for (name = strchr(file, 0);
name > file && name[-1] != '/' && name[-1] != '\\';
--name);
istrlen = strlen(name);
if (istrlen >= sizeof(arhdro.ar_name))
istrlen = sizeof(arhdro.ar_name) - 1;
memset(arhdro.ar_name, ' ', sizeof(arhdro.ar_name));
memcpy(arhdro.ar_name, name, istrlen);
arhdro.ar_name[istrlen] = '/';
sprintf(stmp, "%-10d", fsize);
memcpy(&arhdro.ar_size, stmp, 10);
fwrite(&arhdro, sizeof(arhdro), 1, fo);
fwrite(buf, fsize, 1, fo);
tcc_free(buf);
i_obj++;
fpos += (fsize + sizeof(arhdro));
if (fpos & 1)
fputc(0, fo), ++fpos;
}
hofs = 8 + sizeof(arhdr) + strpos + (funccnt+1) * sizeof(int);
fpos = 0;
if ((hofs & 1)) // align
hofs++, fpos = 1;
// write header
fwrite(ARMAG, 8, 1, fh);
// create an empty archive
if (!funccnt) {
ret = 0;
goto the_end;
}
sprintf(stmp, "%-10d", (int)(strpos + (funccnt+1) * sizeof(int)) + fpos);
memcpy(&arhdr.ar_size, stmp, 10);
fwrite(&arhdr, sizeof(arhdr), 1, fh);
afpos[0] = le2belong(funccnt);
for (i=1; i<=funccnt; i++)
afpos[i] = le2belong(afpos[i] + hofs);
fwrite(afpos, (funccnt+1) * sizeof(int), 1, fh);
fwrite(anames, strpos, 1, fh);
if (fpos)
fwrite("", 1, 1, fh);
// write objects
fseek(fo, 0, SEEK_END);
fsize = ftell(fo);
fseek(fo, 0, SEEK_SET);
buf = tcc_malloc(fsize + 1);
fread(buf, fsize, 1, fo);
fwrite(buf, fsize, 1, fh);
tcc_free(buf);
ret = 0;
the_end:
if (anames)
tcc_free(anames);
if (afpos)
tcc_free(afpos);
if (fh)
fclose(fh);
if (created_file && ret != 0)
remove(created_file);
if (fo)
fclose(fo), remove(tfile);
return ret;
}
/* -------------------------------------------------------------- */
/*
* tiny_impdef creates an export definition file (.def) from a dll
* on MS-Windows. Usage: tiny_impdef library.dll [-o outputfile]"
*
* Copyright (c) 2005,2007 grischka
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of 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.
*
* This program 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 a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifdef TCC_TARGET_PE
ST_FUNC int tcc_tool_impdef(int argc, char **argv)
{
int ret, v, i;
char infile[260];
char outfile[260];
const char *file;
char *p, *q;
FILE *fp, *op;
#ifdef _WIN32
char path[260];
#endif
infile[0] = outfile[0] = 0;
fp = op = NULL;
ret = 1;
p = NULL;
v = 0;
for (i = 1; i < argc; ++i) {
const char *a = argv[i];
if ('-' == a[0]) {
if (0 == strcmp(a, "-v")) {
v = 1;
} else if (0 == strcmp(a, "-o")) {
if (++i == argc)
goto usage;
strcpy(outfile, argv[i]);
} else
goto usage;
} else if (0 == infile[0])
strcpy(infile, a);
else
goto usage;
}
if (0 == infile[0]) {
usage:
fprintf(stderr,
"usage: tcc -impdef library.dll [-v] [-o outputfile]\n"
"create export definition file (.def) from dll\n"
);
goto the_end;
}
if (0 == outfile[0]) {
strcpy(outfile, tcc_basename(infile));
q = strrchr(outfile, '.');
if (NULL == q)
q = strchr(outfile, 0);
strcpy(q, ".def");
}
file = infile;
#ifdef _WIN32
if (SearchPath(NULL, file, ".dll", sizeof path, path, NULL))
file = path;
#endif
ret = tcc_get_dllexports(file, &p);
if (ret || !p) {
fprintf(stderr, "tcc: impdef: %s '%s'\n",
ret == -1 ? "can't find file" :
ret == 1 ? "can't read symbols" :
ret == 0 ? "no symbols found in" :
"unknown file type", file);
ret = 1;
goto the_end;
}
if (v)
printf("-> %s\n", file);
op = fopen(outfile, "wb");
if (NULL == op) {
fprintf(stderr, "tcc: impdef: could not create output file: %s\n", outfile);
goto the_end;
}
fprintf(op, "LIBRARY %s\n\nEXPORTS\n", tcc_basename(file));
for (q = p, i = 0; *q; ++i) {
fprintf(op, "%s\n", q);
q += strlen(q) + 1;
}
if (v)
printf("<- %s (%d symbol%s)\n", outfile, i, &"s"[i<2]);
ret = 0;
the_end:
if (p)
tcc_free(p);
if (fp)
fclose(fp);
if (op)
fclose(op);
return ret;
}
#endif /* TCC_TARGET_PE */
/* -------------------------------------------------------------- */
/*
* 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
*/
/* re-execute the i386/x86_64 cross-compilers with tcc -m32/-m64: */
#if !defined TCC_TARGET_I386 && !defined TCC_TARGET_X86_64
ST_FUNC int tcc_tool_cross(char **argv, int option)
{
fprintf(stderr, "tcc -m%d not implemented\n", option);
return 1;
}
#else
#ifdef _WIN32
#include <process.h>
/* - Empty argument or with space/tab (not newline) requires quoting.
* - Double-quotes at the value require '\'-escape, regardless of quoting.
* - Consecutive (or 1) backslashes at the value all need '\'-escape only if
* followed by [escaped] double quote, else taken literally, e.g. <x\\y\>
* remains literal without quoting or esc, but <x\\"y\> becomes <x\\\\\"y\>.
* - This "before double quote" rule applies also before delimiting quoting,
* e.g. <x\y \"z\> becomes <"x\y \\\"z\\"> (quoting required because space).
*
* https://learn.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments
*/
static char *quote_win32(const char *s)
{
char *o, *r = tcc_malloc(2 * strlen(s) + 3); /* max-esc, quotes, \0 */
int cbs = 0, quoted = !*s; /* consecutive backslashes before current */
for (o = r; *s; *o++ = *s++) {
quoted |= *s == ' ' || *s == '\t';
if (*s == '\\' || *s == '"')
*o++ = '\\';
else
o -= cbs; /* undo cbs escapes, if any (not followed by DQ) */
cbs = *s == '\\' ? cbs + 1 : 0;
}
if (quoted) {
memmove(r + 1, r, o++ - r);
*r = *o++ = '"';
} else {
o -= cbs;
}
*o = 0;
return r; /* don't bother with realloc(r, o-r+1) */
}
static int execvp_win32(const char *prog, char **argv)
{
int ret; char **p;
/* replace all " by \" */
for (p = argv; *p; ++p)
*p = quote_win32(*p);
ret = _spawnvp(P_NOWAIT, prog, (const char *const*)argv);
if (-1 == ret)
return ret;
_cwait(&ret, ret, WAIT_CHILD);
exit(ret);
}
#define execvp execvp_win32
#endif /* _WIN32 */
ST_FUNC int tcc_tool_cross(char **argv, int target)
{
char program[4096];
char *a0 = argv[0];
int prefix = tcc_basename(a0) - a0;
snprintf(program, sizeof program,
"%.*s%s"
#ifdef TCC_TARGET_PE
"-win32"
#endif
"-tcc"
#ifdef _WIN32
".exe"
#endif
, prefix, a0, target == 64 ? "x86_64" : "i386");
if (strcmp(a0, program))
execvp(argv[0] = program, argv);
fprintf(stderr, "tcc: could not run '%s'\n", program);
return 1;
}
#endif /* TCC_TARGET_I386 && TCC_TARGET_X86_64 */
/* -------------------------------------------------------------- */
/* enable commandline wildcard expansion (tcc -o x.exe *.c) */
#ifdef _WIN32
const int _CRT_glob = 1;
#ifndef _CRT_glob
const int _dowildcard = 1;
#endif
#endif
/* -------------------------------------------------------------- */
/* generate xxx.d file */
static char *escape_target_dep(const char *s) {
char *res = tcc_malloc(strlen(s) * 2 + 1);
int j;
for (j = 0; *s; s++, j++) {
if (is_space(*s)) {
res[j++] = '\\';
}
res[j] = *s;
}
res[j] = '\0';
return res;
}
ST_FUNC int gen_makedeps(TCCState *s1, const char *target, const char *filename)
{
FILE *depout;
char buf[1024];
char **escaped_targets;
int i, k, num_targets;
if (!filename) {
/* compute filename automatically: dir/file.o -> dir/file.d */
snprintf(buf, sizeof buf, "%.*s.d",
(int)(tcc_fileextension(target) - target), target);
filename = buf;
}
if(!strcmp(filename, "-"))
depout = fdopen(1, "w");
else
/* XXX return err codes instead of error() ? */
depout = fopen(filename, "w");
if (!depout)
return tcc_error_noabort("could not open '%s'", filename);
if (s1->verbose)
printf("<- %s\n", filename);
escaped_targets = tcc_malloc(s1->nb_target_deps * sizeof(*escaped_targets));
num_targets = 0;
for (i = 0; i<s1->nb_target_deps; ++i) {
for (k = 0; k < i; ++k)
if (0 == strcmp(s1->target_deps[i], s1->target_deps[k]))
goto next;
escaped_targets[num_targets++] = escape_target_dep(s1->target_deps[i]);
next:;
}
fprintf(depout, "%s:", target);
for (i = 0; i < num_targets; ++i)
fprintf(depout, " \\\n %s", escaped_targets[i]);
fprintf(depout, "\n");
if (s1->gen_phony_deps) {
/* Skip first file, which is the c file.
* Only works for single file give on command-line,
* but other compilers have the same limitation */
for (i = 1; i < num_targets; ++i)
fprintf(depout, "%s:\n", escaped_targets[i]);
}
for (i = 0; i < num_targets; ++i)
tcc_free(escaped_targets[i]);
tcc_free(escaped_targets);
fclose(depout);
return 0;
}
/* -------------------------------------------------------------- */
+559
View File
@@ -0,0 +1,559 @@
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(pushfq, 0x9c)
DEF_ASM_OP0(popfq, 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(cqto, 0x4899)
DEF_ASM_OP0(int3, 0xcc)
DEF_ASM_OP0(into, 0xce)
DEF_ASM_OP0(iret, 0xcf)
DEF_ASM_OP0(iretw, 0x66cf)
DEF_ASM_OP0(iretl, 0xcf)
DEF_ASM_OP0(iretq, 0x48cf)
DEF_ASM_OP0(rsm, 0x0faa)
DEF_ASM_OP0(hlt, 0xf4)
DEF_ASM_OP0(wait, 0x9b)
DEF_ASM_OP0(nop, 0x90)
DEF_ASM_OP0(pause, 0xf390)
DEF_ASM_OP0(xlat, 0xd7)
DEF_ASM_OP0L(vmcall, 0xc1, 0, OPC_0F01)
DEF_ASM_OP0L(vmlaunch, 0xc2, 0, OPC_0F01)
DEF_ASM_OP0L(vmresume, 0xc3, 0, OPC_0F01)
DEF_ASM_OP0L(vmxoff, 0xc4, 0, OPC_0F01)
/* 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(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(syscall, 0x0f05)
DEF_ASM_OP0(sysret, 0x0f07)
DEF_ASM_OP0L(sysretq, 0x480f07, 0, 0)
DEF_ASM_OP0(ud2, 0x0f0b)
/* NOTE: we took the same order as gas opcode definition order */
/* Right now we can't express the fact that 0xa1/0xa3 can't use $eax and a
32 bit moffset as operands.
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))
/* The moves are special: the 0xb8 form supports IM64 (the only insn that
does) with REG64. It doesn't support IM32 with REG64, it would use
the full movabs form (64bit immediate). For IM32->REG64 we prefer
the 0xc7 opcode. So disallow all 64bit forms and code the rest by hand. */
ALT(DEF_ASM_OP2(movb, 0xb0, 0, OPC_REG | OPC_BWLX, OPT_IM, OPT_REG))
ALT(DEF_ASM_OP2(mov, 0xb8, 0, OPC_REG, OPT_IM64, OPT_REG64))
ALT(DEF_ASM_OP2(movq, 0xb8, 0, OPC_REG, OPT_IM64, OPT_REG64))
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_REG64))
ALT(DEF_ASM_OP2(movw, 0x0f21, 0, OPC_MODRM | OPC_WLX, OPT_DB, OPT_REG64))
ALT(DEF_ASM_OP2(movw, 0x0f22, 0, OPC_MODRM | OPC_WLX, OPT_REG64, OPT_CR))
ALT(DEF_ASM_OP2(movw, 0x0f23, 0, OPC_MODRM | OPC_WLX, OPT_REG64, OPT_DB))
ALT(DEF_ASM_OP2(movsbw, 0x660fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG16))
ALT(DEF_ASM_OP2(movsbl, 0x0fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP2(movsbq, 0x0fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REGW))
ALT(DEF_ASM_OP2(movswl, 0x0fbf, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32))
ALT(DEF_ASM_OP2(movswq, 0x0fbf, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG))
ALT(DEF_ASM_OP2(movslq, 0x63, 0, OPC_MODRM, OPT_REG32 | OPT_EA, OPT_REG))
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_OP2(movzwq, 0x0fb7, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG))
ALT(DEF_ASM_OP1(pushq, 0x6a, 0, 0, OPT_IM8S))
ALT(DEF_ASM_OP1(push, 0x6a, 0, 0, OPT_IM8S))
ALT(DEF_ASM_OP1(pushw, 0x666a, 0, 0, OPT_IM8S))
ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WLX, OPT_REG64))
ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WLX, OPT_REG16))
ALT(DEF_ASM_OP1(pushw, 0xff, 6, OPC_MODRM | OPC_WLX, OPT_REG64 | OPT_EA))
ALT(DEF_ASM_OP1(pushw, 0x6668, 0, 0, OPT_IM16))
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_REG64))
ALT(DEF_ASM_OP1(popw, 0x58, 0, OPC_REG | OPC_WLX, OPT_REG16))
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(incb, 0xfe, 0, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
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))
DEF_ASM_OP1(callq, 0xff, 2, OPC_MODRM, OPT_INDIR)
ALT(DEF_ASM_OP1(callq, 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_OP1(lcall, 0xff, 3, OPC_MODRM, OPT_EA))
ALT(DEF_ASM_OP1(ljmp, 0xff, 5, OPC_MODRM, OPT_EA))
DEF_ASM_OP1(ljmpw, 0x66ff, 5, OPC_MODRM, OPT_EA)
DEF_ASM_OP1(ljmpl, 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(retq, 0xc3)
ALT(DEF_ASM_OP1(retq, 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, 0x67e3, 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)
DEF_ASM_OP0(fwait, 0x9b)
/* 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 )
/* The *q forms of fxrstor/fxsave use a REX prefix.
If the operand would use extended registers we would have to modify
it instead of generating a second one. Currently that's no
problem with TCC, we don't use extended registers. */
DEF_ASM_OP1(fxsaveq, 0x0fae, 0, OPC_MODRM | OPC_48, OPT_EA )
DEF_ASM_OP1(fxrstorq, 0x0fae, 1, OPC_MODRM | OPC_48, 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(lgdtq, 0x0f01, 2, OPC_MODRM, OPT_EA)
DEF_ASM_OP1(lidt, 0x0f01, 3, OPC_MODRM, OPT_EA)
DEF_ASM_OP1(lidtq, 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_REG16)
DEF_ASM_OP1(sgdt, 0x0f01, 0, OPC_MODRM, OPT_EA)
DEF_ASM_OP1(sgdtq, 0x0f01, 0, OPC_MODRM, OPT_EA)
DEF_ASM_OP1(sidt, 0x0f01, 1, OPC_MODRM, OPT_EA)
DEF_ASM_OP1(sidtq, 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_REG32 | OPT_EA)
ALT(DEF_ASM_OP1(str, 0x660f00, 1, OPC_MODRM, OPT_REG16))
ALT(DEF_ASM_OP1(str, 0x0f00, 1, OPC_MODRM | OPC_48, OPT_REG64))
DEF_ASM_OP1(verr, 0x0f00, 4, OPC_MODRM, OPT_REG | OPT_EA)
DEF_ASM_OP1(verw, 0x0f00, 5, OPC_MODRM, OPT_REG | OPT_EA)
DEF_ASM_OP0L(swapgs, 0x0f01, 7, OPC_MODRM)
/* 486 */
/* bswap can't be applied to 16bit regs */
DEF_ASM_OP1(bswap, 0x0fc8, 0, OPC_REG, OPT_REG32 )
DEF_ASM_OP1(bswapl, 0x0fc8, 0, OPC_REG, OPT_REG32 )
DEF_ASM_OP1(bswapq, 0x0fc8, 0, OPC_REG | OPC_48, OPT_REG64 )
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 )
/* pentium */
DEF_ASM_OP1(cmpxchg8b, 0x0fc7, 1, OPC_MODRM, OPT_EA )
/* AMD 64 */
DEF_ASM_OP1(cmpxchg16b, 0x0fc7, 1, OPC_MODRM | OPC_48, 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 )
/* movd shouldn't accept REG64, but AMD64 spec uses it for 32 and 64 bit
moves, so let's be compatible. */
ALT(DEF_ASM_OP2(movd, 0x0f6e, 0, OPC_MODRM, OPT_EA | OPT_REG64, OPT_MMXSSE ))
ALT(DEF_ASM_OP2(movq, 0x0f6e, 0, OPC_MODRM | OPC_48, OPT_REG64, OPT_MMXSSE ))
ALT(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(movd, 0x0f7e, 0, OPC_MODRM, OPT_MMXSSE, OPT_EA | OPT_REG64 ))
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 ))
ALT(DEF_ASM_OP2(movq, 0x0f7e, 0, OPC_MODRM, OPT_MMXSSE, OPT_EA | OPT_REG64 ))
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(cvtss2si, 0xf30f2d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_REG32 )
ALT(DEF_ASM_OP2(cvtss2si, 0xf30f2d, 0, OPC_MODRM | OPC_48, OPT_EA | OPT_SSE, OPT_REG64 ))
DEF_ASM_OP2(cvtsd2si, 0xf20f2d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_REG32 )
ALT(DEF_ASM_OP2(cvtsd2si, 0xf20f2d, 0, OPC_MODRM | OPC_48, OPT_EA | OPT_SSE, OPT_REG64 ))
DEF_ASM_OP2(cvttps2pi, 0x0f2c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX )
DEF_ASM_OP2(andps, 0x0f54, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
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(sqrtss, 0xf30f51, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
DEF_ASM_OP2(subps, 0x0f5c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
/* sse2 */
DEF_ASM_OP2(andpd, 0x660f54, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE)
DEF_ASM_OP2(sqrtsd, 0xf20f51, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE)
/* movnti should only accept REG32 and REG64, we accept more */
DEF_ASM_OP2(movnti, 0x0fc3, 0, OPC_MODRM, OPT_REG, OPT_EA)
DEF_ASM_OP2(movntil, 0x0fc3, 0, OPC_MODRM, OPT_REG32, OPT_EA)
DEF_ASM_OP2(movntiq, 0x0fc3, 0, OPC_MODRM | OPC_48, OPT_REG64, OPT_EA)
DEF_ASM_OP1(prefetchnta, 0x0f18, 0, OPC_MODRM, OPT_EA)
DEF_ASM_OP1(prefetcht0, 0x0f18, 1, OPC_MODRM, OPT_EA)
DEF_ASM_OP1(prefetcht1, 0x0f18, 2, OPC_MODRM, OPT_EA)
DEF_ASM_OP1(prefetcht2, 0x0f18, 3, OPC_MODRM, OPT_EA)
DEF_ASM_OP1(prefetchw, 0x0f0d, 1, OPC_MODRM, OPT_EA)
DEF_ASM_OP0L(lfence, 0x0fae, 5, OPC_MODRM)
DEF_ASM_OP0L(mfence, 0x0fae, 6, OPC_MODRM)
DEF_ASM_OP0L(sfence, 0x0fae, 7, OPC_MODRM)
DEF_ASM_OP1(clflush, 0x0fae, 7, OPC_MODRM, OPT_EA)
/* Control-Flow Enforcement */
DEF_ASM_OP0L(endbr64, 0xf30f1e, 7, OPC_MODRM)
#undef ALT
#undef DEF_ASM_OP0
#undef DEF_ASM_OP0L
#undef DEF_ASM_OP1
#undef DEF_ASM_OP2
#undef DEF_ASM_OP3
File diff suppressed because it is too large Load Diff
+410
View File
@@ -0,0 +1,410 @@
#ifdef TARGET_DEFS_ONLY
#define EM_TCC_TARGET EM_X86_64
/* relocation type for 32 bit data relocation */
#define R_DATA_32 R_X86_64_32S
#define R_DATA_PTR R_X86_64_64
#define R_JMP_SLOT R_X86_64_JUMP_SLOT
#define R_GLOB_DAT R_X86_64_GLOB_DAT
#define R_COPY R_X86_64_COPY
#define R_RELATIVE R_X86_64_RELATIVE
#define R_NUM R_X86_64_NUM
#define ELF_START_ADDR 0x400000
#define ELF_PAGE_SIZE 0x200000
#define PCRELATIVE_DLLPLT 1
#define RELOCATE_DLLPLT 1
#else /* !TARGET_DEFS_ONLY */
#include "tcc.h"
#ifdef NEED_RELOC_TYPE
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
relocations, returns -1. */
ST_FUNC int code_reloc (int reloc_type)
{
switch (reloc_type) {
case R_X86_64_32:
case R_X86_64_32S:
case R_X86_64_64:
case R_X86_64_GOTPC32:
case R_X86_64_GOTPC64:
case R_X86_64_GOTPCREL:
case R_X86_64_GOTPCRELX:
case R_X86_64_REX_GOTPCRELX:
case R_X86_64_GOTTPOFF:
case R_X86_64_GOT32:
case R_X86_64_GOT64:
case R_X86_64_GLOB_DAT:
case R_X86_64_COPY:
case R_X86_64_RELATIVE:
case R_X86_64_GOTOFF64:
case R_X86_64_TLSGD:
case R_X86_64_TLSLD:
case R_X86_64_DTPOFF32:
case R_X86_64_TPOFF32:
case R_X86_64_DTPOFF64:
case R_X86_64_TPOFF64:
return 0;
case R_X86_64_PC32:
case R_X86_64_PC64:
case R_X86_64_PLT32:
case R_X86_64_PLTOFF64:
case R_X86_64_JUMP_SLOT:
return 1;
}
return -1;
}
/* Returns an enumerator to describe whether and when the relocation needs a
GOT and/or PLT entry to be created. See tcc.h for a description of the
different values. */
ST_FUNC int gotplt_entry_type (int reloc_type)
{
switch (reloc_type) {
case R_X86_64_GLOB_DAT:
case R_X86_64_JUMP_SLOT:
case R_X86_64_COPY:
case R_X86_64_RELATIVE:
return NO_GOTPLT_ENTRY;
/* The following relocs wouldn't normally need GOT or PLT
slots, but we need them for simplicity in the link
editor part. See our caller for comments. */
case R_X86_64_32:
case R_X86_64_32S:
case R_X86_64_64:
case R_X86_64_PC32:
case R_X86_64_PC64:
return AUTO_GOTPLT_ENTRY;
case R_X86_64_GOTTPOFF:
return BUILD_GOT_ONLY;
case R_X86_64_GOT32:
case R_X86_64_GOT64:
case R_X86_64_GOTPC32:
case R_X86_64_GOTPC64:
case R_X86_64_GOTOFF64:
case R_X86_64_GOTPCREL:
case R_X86_64_GOTPCRELX:
case R_X86_64_TLSGD:
case R_X86_64_TLSLD:
case R_X86_64_DTPOFF32:
case R_X86_64_TPOFF32:
case R_X86_64_DTPOFF64:
case R_X86_64_TPOFF64:
case R_X86_64_REX_GOTPCRELX:
case R_X86_64_PLT32:
case R_X86_64_PLTOFF64:
return ALWAYS_GOTPLT_ENTRY;
}
return -1;
}
#ifdef NEED_BUILD_GOT
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
{
Section *plt = s1->plt;
uint8_t *p;
int modrm;
unsigned plt_offset, relofs;
modrm = 0x25;
/* empty PLT: create PLT0 entry that pushes the library identifier
(GOT + PTR_SIZE) and jumps to ld.so resolution routine
(GOT + 2 * PTR_SIZE) */
if (plt->data_offset == 0) {
p = section_ptr_add(plt, 16);
p[0] = 0xff; /* pushl got + PTR_SIZE */
p[1] = modrm + 0x10;
write32le(p + 2, PTR_SIZE);
p[6] = 0xff; /* jmp *(got + PTR_SIZE * 2) */
p[7] = modrm;
write32le(p + 8, PTR_SIZE * 2);
}
plt_offset = plt->data_offset;
/* The PLT slot refers to the relocation entry it needs via offset.
The reloc entry is created below, so its offset is the current
data_offset */
relofs = s1->plt->reloc ? s1->plt->reloc->data_offset : 0;
/* Jump to GOT entry where ld.so initially put the address of ip + 4 */
p = section_ptr_add(plt, 16);
p[0] = 0xff; /* jmp *(got + x) */
p[1] = modrm;
write32le(p + 2, got_offset);
p[6] = 0x68; /* push $xxx */
/* On x86-64, the relocation is referred to by _index_ */
write32le(p + 7, relofs / sizeof (ElfW_Rel) - 1);
p[11] = 0xe9; /* jmp plt_start */
write32le(p + 12, -(plt->data_offset));
return plt_offset;
}
/* relocate the PLT: compute addresses and offsets in the PLT now that final
address for PLT and GOT are known (see fill_program_header) */
ST_FUNC void relocate_plt(TCCState *s1)
{
uint8_t *p, *p_end;
if (!s1->plt)
return;
p = s1->plt->data;
p_end = p + s1->plt->data_offset;
if (p < p_end) {
int x = s1->got->sh_addr - s1->plt->sh_addr - 6;
add32le(p + 2, x);
add32le(p + 8, x - 6);
p += 16;
while (p < p_end) {
add32le(p + 2, x + (s1->plt->data - p));
p += 16;
}
}
if (s1->plt->reloc) {
ElfW_Rel *rel;
int x = s1->plt->sh_addr + 16 + 6;
p = s1->got->data;
for_each_elem(s1->plt->reloc, 0, rel, ElfW_Rel) {
write64le(p + rel->r_offset, x);
x += 16;
}
}
}
#endif
#endif
ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
{
int sym_index, esym_index;
sym_index = ELFW(R_SYM)(rel->r_info);
switch (type) {
case R_X86_64_64:
if (s1->output_type & TCC_OUTPUT_DYN) {
esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
qrel->r_offset = rel->r_offset;
if (esym_index) {
qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_64);
qrel->r_addend = rel->r_addend;
qrel++;
break;
} else {
qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
qrel->r_addend = read64le(ptr) + val;
qrel++;
}
}
add64le(ptr, val);
break;
case R_X86_64_32:
case R_X86_64_32S:
if (s1->output_type & TCC_OUTPUT_DYN) {
/* XXX: this logic may depend on TCC's codegen
now TCC uses R_X86_64_32 even for a 64bit pointer */
qrel->r_offset = rel->r_offset;
qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
/* Use sign extension! */
qrel->r_addend = (int)read32le(ptr) + val;
qrel++;
}
if ((type == R_X86_64_32 ? val != (unsigned)val : val != (int)val)
/* ignore relocation check for stab section */
&& (stab_section == NULL ||
addr < stab_section->sh_addr ||
addr >= (stab_section->sh_addr + stab_section->data_offset))) {
tcc_error_noabort("relocation 'R_X86_64_32[S]' out of range");
}
add32le(ptr, val);
break;
case R_X86_64_PC32:
if (s1->output_type == TCC_OUTPUT_DLL) {
/* DLL relocation */
esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
if (esym_index) {
qrel->r_offset = rel->r_offset;
qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC32);
/* Use sign extension! */
qrel->r_addend = (int)read32le(ptr) + rel->r_addend;
qrel++;
break;
}
}
goto plt32pc32;
case R_X86_64_PLT32:
/* fallthrough: val already holds the PLT slot address */
plt32pc32:
{
long long diff;
diff = (long long)val - addr;
if (diff < -2147483648LL || diff > 2147483647LL) {
#ifdef TCC_TARGET_PE
/* ignore overflow with undefined weak symbols */
if (((ElfW(Sym)*)symtab_section->data)[sym_index].st_shndx != SHN_UNDEF)
#endif
tcc_error_noabort("relocation '%d' out of range", type);
}
add32le(ptr, diff);
}
break;
case R_X86_64_COPY:
break;
case R_X86_64_PLTOFF64:
add64le(ptr, val - s1->got->sh_addr + rel->r_addend);
break;
case R_X86_64_PC64:
if (s1->output_type == TCC_OUTPUT_DLL) {
/* DLL relocation */
esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
if (esym_index) {
qrel->r_offset = rel->r_offset;
qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC64);
qrel->r_addend = read64le(ptr) + rel->r_addend;
qrel++;
break;
}
}
add64le(ptr, val - addr);
break;
case R_X86_64_GLOB_DAT:
case R_X86_64_JUMP_SLOT:
/* They don't need addend */
write64le(ptr, val - rel->r_addend);
break;
case R_X86_64_GOTPCREL:
case R_X86_64_GOTPCRELX:
case R_X86_64_REX_GOTPCRELX:
add32le(ptr, s1->got->sh_addr - addr +
get_sym_attr(s1, sym_index, 0)->got_offset - 4);
break;
case R_X86_64_GOTPC32:
add32le(ptr, s1->got->sh_addr - addr + rel->r_addend);
break;
case R_X86_64_GOTPC64:
add64le(ptr, s1->got->sh_addr - addr + rel->r_addend);
break;
case R_X86_64_GOTTPOFF:
add32le(ptr, val - s1->got->sh_addr);
break;
case R_X86_64_GOT32:
/* we load the got offset */
add32le(ptr, get_sym_attr(s1, sym_index, 0)->got_offset);
break;
case R_X86_64_GOT64:
/* we load the got offset */
add64le(ptr, get_sym_attr(s1, sym_index, 0)->got_offset);
break;
case R_X86_64_GOTOFF64:
add64le(ptr, val - s1->got->sh_addr);
break;
case R_X86_64_TLSGD:
{
static const unsigned char expect[] = {
/* .byte 0x66; lea 0(%rip),%rdi */
0x66, 0x48, 0x8d, 0x3d, 0x00, 0x00, 0x00, 0x00,
/* .word 0x6666; rex64; call __tls_get_addr@PLT */
0x66, 0x66, 0x48, 0xe8, 0x00, 0x00, 0x00, 0x00 };
static const unsigned char replace[] = {
/* mov %fs:0,%rax */
0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00,
/* lea -4(%rax),%rax */
0x48, 0x8d, 0x80, 0x00, 0x00, 0x00, 0x00 };
if (memcmp (ptr-4, expect, sizeof(expect)) == 0) {
ElfW(Sym) *sym;
Section *sec;
int32_t x;
memcpy(ptr-4, replace, sizeof(replace));
rel[1].r_info = ELFW(R_INFO)(0, R_X86_64_NONE);
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
sec = s1->sections[sym->st_shndx];
x = sym->st_value - sec->sh_addr - sec->data_offset;
add32le(ptr + 8, x);
}
else
tcc_error_noabort("unexpected R_X86_64_TLSGD pattern");
}
break;
case R_X86_64_TLSLD:
{
static const unsigned char expect[] = {
/* lea 0(%rip),%rdi */
0x48, 0x8d, 0x3d, 0x00, 0x00, 0x00, 0x00,
/* call __tls_get_addr@PLT */
0xe8, 0x00, 0x00, 0x00, 0x00 };
static const unsigned char replace[] = {
/* data16 data16 data16 mov %fs:0,%rax */
0x66, 0x66, 0x66, 0x64, 0x48, 0x8b, 0x04, 0x25,
0x00, 0x00, 0x00, 0x00 };
if (memcmp (ptr-3, expect, sizeof(expect)) == 0) {
memcpy(ptr-3, replace, sizeof(replace));
rel[1].r_info = ELFW(R_INFO)(0, R_X86_64_NONE);
}
else
tcc_error_noabort("unexpected R_X86_64_TLSLD pattern");
}
break;
case R_X86_64_DTPOFF32:
case R_X86_64_TPOFF32:
{
ElfW(Sym) *sym;
Section *sec;
int32_t x;
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
sec = s1->sections[sym->st_shndx];
x = val - sec->sh_addr - sec->data_offset;
add32le(ptr, x);
}
break;
case R_X86_64_DTPOFF64:
case R_X86_64_TPOFF64:
{
ElfW(Sym) *sym;
Section *sec;
int32_t x;
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
sec = s1->sections[sym->st_shndx];
x = val - sec->sh_addr - sec->data_offset;
add64le(ptr, x);
}
break;
case R_X86_64_NONE:
break;
case R_X86_64_RELATIVE:
#ifdef TCC_TARGET_PE
add32le(ptr, val - s1->pe_imagebase);
#endif
/* do nothing */
break;
default:
fprintf(stderr,"FIXME: handle reloc type %d at %x [%p] to %x\n",
type, (unsigned)addr, ptr, (unsigned)val);
break;
}
}
#endif /* !TARGET_DEFS_ONLY */
+14
View File
@@ -82,6 +82,19 @@ ICONS=(
"apps/scalable/utilities-system-monitor.svg" # system monitor "apps/scalable/utilities-system-monitor.svg" # system monitor
"apps/scalable/drive-harddisk.svg" "apps/scalable/drive-harddisk.svg"
"actions/16/trash-empty.svg" "actions/16/trash-empty.svg"
"places/scalable/folder-blue-home.svg"
"places/scalable/folder-blue-development.svg"
"places/scalable/folder-blue-documents.svg"
"places/scalable/folder-blue-desktop.svg"
"places/scalable/folder-blue-music.svg"
"places/scalable/folder-blue-videos.svg"
"places/scalable/folder-blue-pictures.svg"
"places/scalable/folder-blue-downloads.svg"
"actions/16/edit-copy.svg"
"actions/16/edit-cut.svg"
"actions/16/edit-paste.svg"
"actions/16/edit-rename.svg"
"actions/16/folder-new.svg"
"apps/scalable/pavucontrol.svg" # for volume control app "apps/scalable/pavucontrol.svg" # for volume control app
"actions/16/media-pause.svg" "actions/16/media-pause.svg"
"actions/16/media-play.svg" "actions/16/media-play.svg"
@@ -95,6 +108,7 @@ ICONS=(
"apps/scalable/gnome-logout.svg" "apps/scalable/gnome-logout.svg"
"apps/scalable/lock.svg" "apps/scalable/lock.svg"
"apps/scalable/sleep.svg" "apps/scalable/sleep.svg"
"apps/scalable/kolourpaint.svg" # paint app
) )
copied=0 copied=0
+1
View File
@@ -30,6 +30,7 @@ APPS=(
"video|apps/scalable/multimedia-video-player.svg" "video|apps/scalable/multimedia-video-player.svg"
"bluetooth|apps/scalable/bluetooth.svg" "bluetooth|apps/scalable/bluetooth.svg"
"rpgdemo|apps/scalable/utilities-terminal.svg" "rpgdemo|apps/scalable/utilities-terminal.svg"
"paint|apps/scalable/kolourpaint.svg"
) )
installed=0 installed=0