ci: add Linux build workflow + los4 GUI fixes + bump to 0.1.1

- Add .github/workflows/build-linux.yml: auto-build self-contained
  linux-x64 paze on push/tag, smoke-test with hello.pe, publish
  tar.gz+zip artifacts and GitHub Release on v* tags.

- Fix LeonOS 4 (los4) syscalls: use int 0x80 (0xCD 0x80) instead of
  syscall (0x0F 0x05) in Los4Runtime and StartupStubs, matching the
  real doomlauncher.elf ABI.

- Fix X64CodeGenerator GenCallArgs: allocate spill slots for register
  arguments under SysV ABI to avoid overwriting caller stack temporaries
  (was clobbering &gui_fb during malloc call).

- Fix los4 malloc/calloc: switch from unsupported SYS_mmap to a 1MB
  BSS static heap pool with bump pointer allocation.

- Fix ElfWriterLos4 WritePhdr: resolve Write64At overload ambiguity
  that corrupted the program header table and left holes in .text.

- Fix los4 GUI: use PRESENT_WINDOW ioctl with self-rendered framebuffer
  (8x16 font + ARGB32 color format), correct app_event struct layout
  (35 bytes, no trailing reserved field).

- Bump version 0.1.0 -> 0.1.1 (csproj, wixproj, Product.wxs install
  dir + registry paths).
这个提交包含在:
2026-08-03 19:44:40 +08:00
父节点 324edb14b0
当前提交 9ab3a0225b
修改 15 个文件,包含 991 行新增206 行删除
+135
查看文件
@@ -0,0 +1,135 @@
name: build-linux
on:
push:
branches: [ main, master ]
tags: [ 'v*' ]
pull_request:
branches: [ main, master ]
workflow_dispatch:
jobs:
build:
name: Build paze for Linux x64
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup .NET 10
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
dotnet-quality: 'preview'
- name: Restore
run: dotnet restore src/PazeE.Compiler/PazeE.Compiler.csproj
- name: Determine channel & version
id: meta
run: |
if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then
CHANNEL="release"
else
CHANNEL="alpha"
fi
VERSION=$(dotnet msbuild src/PazeE.Compiler/PazeE.Compiler.csproj \
-p:BuildChannel=$CHANNEL \
-getProperty:Version \
-nologo)
echo "channel=$CHANNEL" >> "$GITHUB_OUTPUT"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "Channel: $CHANNEL Version: $VERSION"
- name: Publish (self-contained, linux-x64)
run: |
dotnet publish src/PazeE.Compiler/PazeE.Compiler.csproj \
-c Release \
-p:BuildChannel=${{ steps.meta.outputs.channel }} \
-r linux-x64 \
--self-contained true \
-p:PublishSingleFile=true \
-p:EnableCompressionInSingleFile=true
- name: Stage artifacts
run: |
STAGE="staging/paze-${{ steps.meta.outputs.version }}-linux-x64"
mkdir -p "$STAGE/bin"
cp -v publish/${{ steps.meta.outputs.version }}/bin/* "$STAGE/bin/" 2>/dev/null || true
# 单文件模式下 paze 主程序即 paze.dll/paze.exe → 重命名为 paze
if [ -f "$STAGE/bin/paze" ]; then
chmod +x "$STAGE/bin/paze"
fi
# 包含测试源文件以便验证
mkdir -p "$STAGE/tests"
cp -v tests/*.pe "$STAGE/tests/" 2>/dev/null || true
# 生成版本说明
cat > "$STAGE/VERSION.txt" <<EOF
PazeE Compiler
Version: ${{ steps.meta.outputs.version }}
Channel: ${{ steps.meta.outputs.channel }}
Target: linux-x64 (self-contained .NET 10)
Commit: ${GITHUB_SHA}
Built: ${GITHUB_RUN_ID}
EOF
# 打包
cd staging
tar -czf ../paze-${{ steps.meta.outputs.version }}-linux-x64.tar.gz *
zip -r -q ../paze-${{ steps.meta.outputs.version }}-linux-x64.zip *
cd ..
ls -lh paze-*.tar.gz paze-*.zip
- name: Smoke test — compile hello.pe
run: |
BIN="staging/paze-${{ steps.meta.outputs.version }}-linux-x64/bin"
if [ -f "$BIN/paze" ]; then
"$BIN/paze" tests/hello.pe --target linux -o /tmp/hello.elf
file /tmp/hello.elf
/tmp/hello.elf || true
elif [ -f "$BIN/paze.dll" ]; then
dotnet "$BIN/paze.dll" tests/hello.pe --target linux -o /tmp/hello.elf
file /tmp/hello.elf
/tmp/hello.elf || true
else
echo "WARN: paze binary not found, listing bin/:"
ls -la "$BIN"
fi
- name: Upload artifact (tar.gz)
uses: actions/upload-artifact@v4
with:
name: paze-${{ steps.meta.outputs.version }}-linux-x64-tar
path: paze-${{ steps.meta.outputs.version }}-linux-x64.tar.gz
if-no-files-found: error
- name: Upload artifact (zip)
uses: actions/upload-artifact@v4
with:
name: paze-${{ steps.meta.outputs.version }}-linux-x64-zip
path: paze-${{ steps.meta.outputs.version }}-linux-x64.zip
if-no-files-found: error
release:
name: Publish GitHub Release
needs: build
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Create release
uses: softprops/action-gh-release@v2
with:
name: PazeE ${{ github.ref_name }}
tag_name: ${{ github.ref_name }}
generate_release_notes: true
files: |
artifacts/**/*.tar.gz
artifacts/**/*.zip
+6 -6
查看文件
@@ -309,12 +309,12 @@ public sealed class ElfWriter : IExecutableWriter
{
Write32At(f, type);
Write32At(f, flags);
Write64At(f, off);
Write64At(f, vaddr);
Write64At(f, vaddr); // p_paddr = p_vaddr
Write64At(f, filesz);
Write64At(f, memsz);
Write64At(f, align);
int o1 = f.Count; Write64At(f, o1, off);
int o2 = f.Count; Write64At(f, o2, vaddr);
int o3 = f.Count; Write64At(f, o3, vaddr); // p_paddr = p_vaddr
int o4 = f.Count; Write64At(f, o4, filesz);
int o5 = f.Count; Write64At(f, o5, memsz);
int o6 = f.Count; Write64At(f, o6, align);
}
private static void WriteSym(List<byte> s, int name, int info, int other, int shndx, long value)
+42 -8
查看文件
@@ -5,7 +5,7 @@ namespace PazeE.Compiler.Binary;
/// <summary>LeonOS 4 ELF64 (x86-64) 静态可执行文件写入器。
/// 无动态链接(无 PLT/GOT/.dynsym/.dynamic/PT_INTERP),运行时函数由 Los4Runtime 静态注入 .text。
/// 系统调用通过 int 0x80(与 Linux x86_64 同调用号),ELF 布局与 doomlauncher.elf 一致:
/// 系统调用通过 syscall 指令(0x0F 0x05,寄存器约定同 Linux x86_64),ELF 布局与 doomlauncher.elf 一致:
/// 3 个 PT_LOAD.text RX / .rodata R / .data+.bss RW+ PT_GNU_STACK,基址 0x400000。</summary>
public sealed class ElfWriterLos4 : IExecutableWriter
{
@@ -26,7 +26,7 @@ public sealed class ElfWriterLos4 : IExecutableWriter
var data = new List<byte>(img.Data.Data);
// ---- 2. 静态运行时(先于布局,以便获取 BSS 大小)----
var (rtCode, rtOffsets, rdataRefs, bssRefs, rtBssSize) = Los4Runtime.Generate();
var (rtCode, rtOffsets, rdataRefs, rdataBinRefs, bssRefs, rtBssSize) = Los4Runtime.Generate();
// BSS = 用户 BSS + 运行时 BSSgui_fd/gui_win_id 等持久状态)
int userBssSize = img.Bss.BssSize;
@@ -56,6 +56,24 @@ public sealed class ElfWriterLos4 : IExecutableWriter
}
}
// ---- 2c. 运行时引用的 .rodata 二进制数据 → 追加到 rodata,记录偏移 ----
// 如 PSF 字体数据(FontData 2048 字节),由 paze_font_ptr() 返回其 rodata 地址。
var rdataBinOff = new List<(byte[] data, long offset)>();
foreach (var (off, binData) in rdataBinRefs)
{
long binOffset = -1;
for (int i = 0; i < rdataBinOff.Count; i++)
{
if (ReferenceEquals(rdataBinOff[i].data, binData)) { binOffset = rdataBinOff[i].offset; break; }
}
if (binOffset < 0)
{
binOffset = rodata.Count;
rodata.AddRange(binData);
rdataBinOff.Add((binData, binOffset));
}
}
// ---- 3. 收集所有 fixup ----
var fixups = new List<(ImageSection sec, int off, FixupKind kind, string sym)>();
foreach (var f in img.Fixups) fixups.Add((f.Section, f.Offset, f.Kind, f.Symbol));
@@ -115,6 +133,22 @@ public sealed class ElfWriterLos4 : IExecutableWriter
Write64At(text, rtBase + off, strVaddr);
}
// ---- 运行时 RData 二进制数据引用回填 ----
// 运行时代码中 mov r64, &bin 的 8 字节占位 → 填入二进制数据在 .rodata 的虚拟地址
foreach (var (off, binData) in rdataBinRefs)
{
long binOffset = -1;
for (int i = 0; i < rdataBinOff.Count; i++)
{
if (ReferenceEquals(rdataBinOff[i].data, binData)) { binOffset = rdataBinOff[i].offset; break; }
}
if (binOffset >= 0)
{
long binVaddr = rodataVaddr + binOffset;
Write64At(text, rtBase + off, binVaddr);
}
}
// ---- 运行时 BSS 全局引用回填 ----
// 运行时 BSS 紧跟用户 BSS:全局在 [bssVaddr + userBssSize + bssOff] 处。
foreach (var (off, name, bssOff) in bssRefs)
@@ -200,12 +234,12 @@ public sealed class ElfWriterLos4 : IExecutableWriter
{
Write32At(f, type);
Write32At(f, flags);
Write64At(f, off);
Write64At(f, vaddr);
Write64At(f, vaddr); // p_paddr = p_vaddr
Write64At(f, filesz);
Write64At(f, memsz);
Write64At(f, align);
int o1 = f.Count; Write64At(f, o1, off);
int o2 = f.Count; Write64At(f, o2, vaddr);
int o3 = f.Count; Write64At(f, o3, vaddr); // p_paddr = p_vaddr
int o4 = f.Count; Write64At(f, o4, filesz);
int o5 = f.Count; Write64At(f, o5, memsz);
int o6 = f.Count; Write64At(f, o6, align);
}
private static long Align(long v, int a) => a <= 1 ? v : (v + a - 1) & ~(long)(a - 1);
+313 -127
查看文件
@@ -1,8 +1,9 @@
namespace PazeE.Compiler.Binary;
/// <summary>LeonOS 4 静态运行时:通过 int 0x80 系统调用提供标准 C 库函数实现。
/// <summary>LeonOS 4 静态运行时:通过 syscall 指令提供标准 C 库函数实现。
/// 所有函数以 System V AMD64 ABI 调用,注入到 .text 段末尾,由 ElfWriterLos4 解析外部符号引用。
/// LeonOS 4 系统调用约定与 Linux x86_64 一致(rax=调用号, rdi/rsi/rdx...=参数),用 int 0x80 而非 syscall。</summary>
/// LeonOS 4 系统调用约定与 Linux x86_64 一致(rax=调用号, rdi/rsi/rdx/r10/r8/r9=参数),使syscall 指令(0x0F 0x05)。
/// GUI 设备由 LeonOS shell 预打开为 fd=3,所有 GUI 函数直接使用 fd=3(与 libc.a 行为一致)。</summary>
public static class Los4Runtime
{
public const int SYS_read = 0;
@@ -24,6 +25,7 @@ public static class Los4Runtime
private const long LEONOS_GUI_IOCTL_WINDOW_EVENT = 0x4c475745L;
private const long LEONOS_GUI_IOCTL_WAIT_WINDOW_EVENT = 0x4c475457L;
private const long LEONOS_GUI_IOCTL_DESTROY_WINDOW = 0x4c475744L;
private const long LEONOS_GUI_IOCTL_PRESENT_WINDOW = 0x4c475046L;
// LeonOS GUI 应用事件类型(来自 gui.h LEONOS_GUI_APP_EVENT_*
private const int LEONOS_GUI_APP_EVENT_CLOSE = 1;
@@ -36,12 +38,150 @@ public static class Los4Runtime
private const int MAP_PRIVATE = 0x02;
private const int MAP_ANONYMOUS = 0x20;
public static (byte[] code, Dictionary<string, int> offsets, List<(int off, string content)> rdataRefs, List<(int off, string name, int bssOff)> bssRefs, int bssSize) Generate()
/// <summary>PSF1 8×16 位图字体的 ASCII 部分(128 字形 × 16 字节 = 2048 字节),
/// 从 lat15_vga16.psf 提取,用于 los2w 模拟器像素文本渲染(PRESENT_WINDOW)。</summary>
private static readonly byte[] FontData = new byte[2048] {
0x00,0x00,0x3C,0x42,0x99,0xA5,0xA1,0xA1,0xA5,0x99,0x42,0x3C,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDB,0xDB,0x00,0x00,0x00,0x00,
0x00,0x00,0xF1,0x5B,0x55,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x10,0x38,0x7C,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0xCC,0xCF,0xED,0xFF,0xFC,0xDF,0xCC,0xCC,0xCC,0xCC,0x00,0x00,0x00,0x00,
0x00,0x00,0x03,0x3E,0x66,0xCF,0xDB,0xDB,0xF3,0x66,0x7C,0xC0,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x66,0x3C,0x66,0x66,0x66,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
0x00,0x00,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x38,0x44,0xBA,0xB2,0xAA,0x44,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x70,0xD8,0x30,0x18,0xD8,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x0C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x0C,0x38,0x00,
0x00,0x30,0x70,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0xE0,0x30,0x62,0x36,0xEC,0x18,0x30,0x66,0xCE,0x9E,0x3E,0x06,0x06,0x00,0x00,
0x60,0x30,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x66,0x00,0x00,0x00,0x00,
0x00,0x00,0x7F,0xDB,0xDB,0xDB,0x7B,0x1B,0x1B,0x1B,0x1B,0x1B,0x00,0x00,0x00,0x00,
0x00,0x7C,0xC6,0x60,0x38,0x6C,0xC6,0xC6,0x6C,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,
0x0C,0x18,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
0x10,0x38,0x6C,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x0C,0x06,0xFF,0x06,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x30,0x60,0xFF,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00,
0x76,0xDC,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
0x30,0x18,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x62,0x66,0xFE,0x00,0x00,0x00,0x00,
0x10,0x38,0x44,0xFE,0x66,0x62,0x68,0x78,0x68,0x62,0x66,0xFE,0x00,0x00,0x00,0x00,
0x6C,0x6C,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x62,0x66,0xFE,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00,
0x18,0x18,0x7C,0xC6,0xC2,0xC0,0x7C,0x06,0x06,0x86,0xC6,0x7C,0x18,0x18,0x00,0x00,
0x00,0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00,
0x00,0x00,0x38,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
0x00,0x30,0x30,0x30,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00,
0x00,0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00,
0x00,0x00,0x38,0x6C,0xC6,0xC6,0xD6,0xD6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00,
0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00,
0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00,
0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00,
0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00,
0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00,
0x00,0x00,0x38,0x60,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
0x00,0x00,0xFE,0xC6,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00,
0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00,
0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x7C,0xC6,0xC6,0xDE,0xDE,0xDE,0xDC,0xC0,0x7C,0x00,0x00,0x00,0x00,
0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00,
0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x00,0x00,0x00,0x00,
0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00,
0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00,
0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xDE,0xC6,0xC6,0x66,0x3A,0x00,0x00,0x00,0x00,
0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
0x00,0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,
0x00,0x00,0xE6,0x66,0x66,0x6C,0x78,0x78,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,
0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00,
0x00,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
0x00,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xDE,0x7C,0x0C,0x0E,0x00,0x00,
0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,
0x00,0x00,0x7C,0xC6,0xC6,0x60,0x38,0x0C,0x06,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
0x00,0x00,0x7E,0x7E,0x5A,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x10,0x00,0x00,0x00,0x00,
0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0xEE,0x6C,0x00,0x00,0x00,0x00,
0x00,0x00,0xC6,0xC6,0x6C,0x7C,0x38,0x38,0x7C,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00,
0x00,0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
0x00,0x00,0xFE,0xC6,0x86,0x0C,0x18,0x30,0x60,0xC2,0xC6,0xFE,0x00,0x00,0x00,0x00,
0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x06,0x02,0x00,0x00,0x00,0x00,
0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00,
0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,
0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
0x00,0x00,0xE0,0x60,0x60,0x78,0x6C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
0x00,0x00,0x1C,0x0C,0x0C,0x3C,0x6C,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
0x00,0x00,0x38,0x6C,0x64,0x60,0xF0,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0xCC,0x78,0x00,
0x00,0x00,0xE0,0x60,0x60,0x6C,0x76,0x66,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,
0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,
0x00,0x00,0xE0,0x60,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0xE6,0x00,0x00,0x00,0x00,
0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xEC,0xFE,0xD6,0xD6,0xD6,0xD6,0xC6,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00,
0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0x0C,0x1E,0x00,
0x00,0x00,0x00,0x00,0x00,0xDC,0x76,0x66,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0x60,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,0x00,
0x00,0x00,0x10,0x30,0x30,0xFC,0x30,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0x6C,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xC6,0x6C,0x38,0x38,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0xF8,0x00,
0x00,0x00,0x00,0x00,0x00,0xFE,0xCC,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00,
0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00,
0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00,
0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x30,0x18,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00
};
public const int HeapPoolSize = 0x100000; // 1MB BSS 堆池
public static (byte[] code, Dictionary<string, int> offsets, List<(int off, string content)> rdataRefs, List<(int off, byte[] data)> rdataBinRefs, List<(int off, string name, int bssOff)> bssRefs, int bssSize) Generate()
{
var b = new Rt();
// 预分配 GUI 持久状态(BSS 全局):gui_fd, gui_win_id
b.AllocBss("gui_fd", 8);
b.AllocBss("gui_win_id", 8);
// 分配 BSS 堆池与分配指针
b.AllocBss("heap_pool", HeapPoolSize);
b.AllocBss("heap_ptr", 8);
b.AllocBss("gui_fd", 4); // GUI 设备 fd(打开后存储)
b.AllocBss("gui_win_id", 4); // 当前窗口 ID
var o = new Dictionary<string, int>();
void Reg(string n, Action<Rt> g) { if (!o.ContainsKey(n)) { o[n] = b.Pos; b.MarkFunc(n); g(b); } }
@@ -72,16 +212,31 @@ public static class Los4Runtime
Reg("scanf", GenScanf);
Reg("sscanf", GenSscanf);
Reg("time_utc_raw", GenTimeGetUtcRaw);
// GUI 函数
Reg("gui_init", GenGuiInit);
Reg("gui_window_create", GenGuiWindowCreate);
Reg("gui_window_text", GenGuiWindowText);
Reg("gui_window_present", GenGuiWindowPresent);
Reg("gui_event_poll", GenGuiEventPoll);
Reg("gui_event_wait", GenGuiEventWait);
Reg("gui_window_destroy", GenGuiWindowDestroy);
Reg("gui_cleanup", GenGuiCleanup);
return (b.Finish(), o, b.RdataRefs, b.BssRefs, b.BssSize);
Reg("open", GenOpen);
Reg("close", GenClose);
// Los4 GUI 辅助函数(GUI 逻辑由 LibcDecls.cs C 代码实现,仅提供底层 ioctl + 字体指针)
Reg("paze_ioctl", GenPazeIoctl);
Reg("paze_font_ptr", GenPazeFontPtr);
return (b.Finish(), o, b.RdataRefs, b.RdataBinRefs, b.BssRefs, b.BssSize);
}
// ============ Los4 GUI 底层辅助 ============
/// int paze_ioctl(int fd, unsigned long req, void *arg) — ioctl 系统调用封装。
/// 参数已在 SysV ABI 寄存器中(rdi=fd, rsi=req, rdx=arg),直接发 syscall。
/// </summary>
private static void GenPazeIoctl(Rt b)
{
b.MovEax(SYS_ioctl); b.Syscall(); b.Ret();
}
/// unsigned char *paze_font_ptr(void) — 返回 PSF 字体数据在 .rodata 中的地址。
/// FontData2048 字节 = 128 字形 × 16 字节)由 ElfWriterLos4 追加到 rodata。
/// </summary>
private static void GenPazeFontPtr(Rt b)
{
b.MovImm64RdataBinRef(0, FontData); // rax = &FontData (rodata)
b.Ret();
}
// ============ 时间 ============
@@ -97,14 +252,14 @@ public static class Los4Runtime
b.MovImm64RdataRef(7, Los4SystemDevice); // rdi = "0:/dev/leonos_system"
b.Xor(6, 6); // rsi = 0 (O_RDONLY)
b.Xor(2, 2); // rdx = 0 (mode)
b.MovEax(SYS_open); b.Int80(); // rax = fd
b.MovEax(SYS_open); b.Syscall(); // rax = fd
b.StoreRbp(-8, 0); // [rbp-8] = fd
// ioctl(fd, LEONOS_IOCTL_TIME_INFO, &buf): rdi=fd, rsi=request, rdx=&buf
b.LoadRbp(7, -8); // rdi = fd
b.MovImm64(6, LEONOS_IOCTL_TIME_INFO); // rsi = request
b.LeaRbp(2, -80); // rdx = &buf
b.MovEax(SYS_ioctl); b.Int80();
b.MovEax(SYS_ioctl); b.Syscall();
// rax = buf.unix_seconds (偏移 0)
b.LoadRbp(0, -80);
@@ -112,86 +267,72 @@ public static class Los4Runtime
// close(fd)(保留 rax
b.PushR(0);
b.LoadRbp(7, -8);
b.MovEax(SYS_close); b.Int80();
b.MovEax(SYS_close); b.Syscall();
b.PopR(0); // rax = unix_seconds
b.Leave(); b.Ret();
}
// ============ GUI ============
// LeonOS 4 GUIopen("/dev/leonos_gui") + ioctl 实现。gui_fd/gui_win_id 存于 BSS 全局
// 结构体布局(来自 leonos/gui.h):
// LeonOS 4 GUIfd=3 硬编码(由 shell 预打开),ioctl 实现
// 与 libc.a 行为完全一致:所有 GUI 函数直接使用 fd=3,无需 open/close。
// 系统调用使用 syscall 指令(0x0F 0x05),寄存器约定同 Linux x86_64。
// 结构体布局(来自 leonos/gui.h,通过反编译 libc.a 验证):
// leonos_gui_create { u32 width, height; char *title, *text; u32 flags; } = 32 字节
// leonos_fb_text { u32 x, y, fg, bg; char *text; } = 24 字节
// leonos_gui_app_event{ u32 window_id, type; i32 x,y,dx,dy; u32 width,height;
// u8 buttons, keycode, pressed, reserved; } = 40 字节
// leonos_gui_wait_app_event { event[40]; u32 timeout_ms; } = 44 字节
// u8 buttons, keycode, pressed, reserved; } = 36 字节
// leonos_gui_wait_app_event { event[36]; u32 timeout_ms; } = 40 字节
// ioctl arg 约定(反编译 libc.a 确认):CREATE/FB_TEXT/WINDOW_EVENT/WAIT 传结构体指针;
// DESTROY_WINDOW 传 window_id 值(非指针)。
// int gui_init(void) — 打开 GUI 设备fd 存入 gui_fd
// int gui_init(void) — 打开 GUI 设备 fdlos2w shell 不预打开 fd=3
private static void GenGuiInit(Rt b)
{
int retOk = b.Lbl(), retFail = b.Lbl();
b.PushRbp(); b.MovRbpRsp(); b.SubRsp(16);
// if (gui_fd != 0) return 0;
b.MovImm64BssRef(0, "gui_fd"); // rax = &gui_fd
b.LoadReg32(0, 0); // eax = gui_fd
b.Test(0, 0);
b.Jne(retOk);
// fd = open("0:/dev/leonos_gui", O_RDWR=2, 0)
b.MovImm64RdataRef(7, Los4GuiDevice); // rdi = device path
b.MovImm64(6, 2); // rsi = O_RDWR
b.Xor(2, 2); // rdx = 0
b.MovEax(SYS_open); b.Int80(); // rax = fd
b.Test(0, 0);
b.Js(retFail); // fd < 0 → -1
// gui_fd = fd
b.Mov(1, 0); // rcx = fd(保留)
b.MovImm64BssRef(0, "gui_fd"); // rax = &gui_fd
b.StoreReg32(0, 1); // [rax] = ecx
b.Mark(retOk);
b.Xor(0, 0); // return 0
b.Leave(); b.Ret();
b.Mark(retFail);
b.MovImm64(0, -1); // return -1
b.PushRbp(); b.MovRbpRsp();
// open("0:/dev/leonos_gui", O_RDWR=2, 0): rdi=path, rsi=2, rdx=0
b.MovImm64RdataRef(7, Los4GuiDevice);
b.MovImm64(6, 2); // rsi = O_RDWR
b.Xor(2, 2); // rdx = 0 (mode)
b.MovEax(SYS_open); b.Syscall(); // rax = fd
// 保存到 BSS gui_fd
b.MovImm64BssRef(2, "gui_fd"); // rdx = &gui_fd
b.StoreReg32(2, 0); // *gui_fd = fd (int)
b.Leave(); b.Ret();
}
// int gui_window_create(const char *title, int width, int height)
// int gui_window_create(const char *title, const char *text, int width, int height)
private static void GenGuiWindowCreate(Rt b)
{
// 参数:rdi=title(7), rsi=width(6), rdx=height(2)
// 栈布局:[rbp-8]=title, [rbp-16]=width, [rbp-24]=height, [rbp-56..-25]=gui_create(32 字节)
// 参数:rdi=title(7), rsi=text(6), rdx=width(2), rcx=height(1)
// 栈布局:[rbp-8]=title, [rbp-16]=text, [rbp-24]=width, [rbp-32]=height, [rbp-64..-33]=gui_create(32 字节)
int retFail = b.Lbl();
b.PushRbp(); b.MovRbpRsp(); b.SubRsp(64);
b.PushRbp(); b.MovRbpRsp(); b.SubRsp(72);
b.StoreRbp(-8, 7); // 保存 title
b.StoreRbp(-16, 6); // 保存 width
b.StoreRbp(-24, 2); // 保存 height
// gui_init()(内部已处理重复调用)
b.StoreRbp(-16, 6); // 保存 text
b.StoreRbp(-24, 2); // 保存 width
b.StoreRbp(-32, 1); // 保存 height
// gui_init()(打开 GUI 设备,fd 存入 BSS gui_fd
b.CallName("gui_init");
b.Test(0, 0);
b.Js(retFail); // gui_init < 0 → -1
// 构造 leonos_gui_create @ [rbp-56],用 rdi 作游标逐字段填充
b.LeaRbp(7, -56); // rdi = &gc
b.LoadRbp(0, -16); b.StoreReg32(7, 0); // gc.width = width ([rdi+0])
// 构造 leonos_gui_create @ [rbp-64],用 rdi 作游标逐字段填充
b.LeaRbp(7, -64); // rdi = &gc
b.LoadRbp(0, -24); b.StoreReg32(7, 0); // gc.width = width ([rdi+0])
b.AddImm(7, 4);
b.LoadRbp(0, -24); b.StoreReg32(7, 0); // gc.height = height ([rdi+4])
b.LoadRbp(0, -32); b.StoreReg32(7, 0); // gc.height = height ([rdi+4])
b.AddImm(7, 4);
b.LoadRbp(0, -8); b.StoreReg64(7, 0); // gc.title = title ([rdi+8])
b.AddImm(7, 8);
b.Xor(0, 0); b.StoreReg64(7, 0); // gc.text = NULL ([rdi+16])
b.LoadRbp(0, -16); b.StoreReg64(7, 0); // gc.text = text ([rdi+16]) — 初始窗口文本
b.AddImm(7, 8);
b.Xor(0, 0); b.StoreReg32(7, 0); // gc.flags = 0 ([rdi+24])
// ioctl(gui_fd, CREATE_WINDOW, &gc)
b.MovImm64BssRef(7, "gui_fd"); b.LoadReg32(7, 7); // rdi = gui_fd
b.MovImm64BssRef(7, "gui_fd"); // rdi = &gui_fd
b.LoadReg32(7, 0); // rdi = gui_fd (int)
b.MovImm64(6, LEONOS_GUI_IOCTL_CREATE_WINDOW); // rsi = request
b.LeaRbp(2, -56); // rdx = &gc
b.MovEax(SYS_ioctl); b.Int80(); // rax = window_id
b.LeaRbp(2, -64); // rdx = &gc
b.MovEax(SYS_ioctl); b.Syscall(); // rax = window_id
b.Test(0, 0);
b.Js(retFail); // < 0 → -1
// gui_win_id = rax
b.Mov(1, 0); // rcx = id(保留)
b.MovImm64BssRef(0, "gui_win_id");
b.StoreReg32(0, 1); // gui_win_id = id
b.Jle(retFail); // <= 0 → -1(与 libc.a 一致:result > 0 才成功)
b.Xor(0, 0); // return 0
b.Leave(); b.Ret();
b.Mark(retFail);
@@ -213,10 +354,11 @@ public static class Los4Runtime
b.AddImm(10, 4); b.StoreReg32(10, 9); // [r10+12]= bg (r9)
b.AddImm(10, 4); b.StoreReg64(10, 1); // [r10+16]= text(rcx)
// ioctl(gui_fd, FB_TEXT, &fbtext)
b.MovImm64BssRef(7, "gui_fd"); b.LoadReg32(7, 7); // rdi = gui_fd
b.MovImm64BssRef(7, "gui_fd"); // rdi = &gui_fd
b.LoadReg32(7, 0); // rdi = gui_fd
b.MovImm64(6, LEONOS_GUI_IOCTL_FB_TEXT); // rsi = request
b.LeaRbp(2, -24); // rdx = &fbtext
b.MovEax(SYS_ioctl); b.Int80();
b.MovEax(SYS_ioctl); b.Syscall();
b.Xor(0, 0); // return 0
b.Leave(); b.Ret();
}
@@ -283,7 +425,7 @@ public static class Los4Runtime
private static void GenGuiEventPoll(Rt b)
{
// 参数:rdi=ev(7)
// 结构 leonos_gui_app_event @ [rbp-48]40 字节)
// 结构 leonos_gui_app_event @ [rbp-48]36 字节,清零 40 字节对齐
int noEvent = b.Lbl();
b.PushRbp(); b.MovRbpRsp(); b.SubRsp(56);
b.StoreRbp(-56, 7); // 保存 ev 指针到 [rbp-56]
@@ -292,10 +434,11 @@ public static class Los4Runtime
b.LeaRbp(1, -48);
for (int i = 0; i < 40; i += 8) { b.StoreReg64(1, 0); b.AddImm(1, 8); }
// ioctl(gui_fd, WINDOW_EVENT, &event)
b.MovImm64BssRef(7, "gui_fd"); b.LoadReg32(7, 7);
b.MovImm64(6, LEONOS_GUI_IOCTL_WINDOW_EVENT);
b.LeaRbp(2, -48);
b.MovEax(SYS_ioctl); b.Int80(); // rax = 0(无事件) / 1(有事件)
b.MovImm64BssRef(7, "gui_fd"); // rdi = &gui_fd
b.LoadReg32(7, 0); // rdi = gui_fd
b.MovImm64(6, LEONOS_GUI_IOCTL_WINDOW_EVENT); // rsi = request
b.LeaRbp(2, -48); // rdx = &event
b.MovEax(SYS_ioctl); b.Syscall(); // rax = 0(无事件) / 1(有事件)
b.Test(0, 0);
b.Jle(noEvent); // rax <= 0 → ev->type=0, return 0
// 翻译事件
@@ -315,66 +458,84 @@ public static class Los4Runtime
private static void GenGuiEventWait(Rt b)
{
// 参数:rdi=ev(7), rsi=timeout_ms(6)
// 结构 leonos_gui_wait_app_event @ [rbp-56]44 字节):event[40] + timeout_ms[4]
// 结构 leonos_gui_wait_app_event @ [rbp-56]40 字节):event[36] + timeout_ms[4]
// timeout_ms 在结构体 offset 36 = [rbp-20]
int noEvent = b.Lbl();
b.PushRbp(); b.MovRbpRsp(); b.SubRsp(72);
b.StoreRbp(-64, 7); // 保存 ev
b.StoreRbp(-72, 6); // 保存 timeout_ms
// 清零 wait 结构
// 清零 wait 结构(48 字节,覆盖 40 字节结构体 + 对齐填充)
b.Xor(0, 0);
b.LeaRbp(1, -56);
for (int i = 0; i < 48; i += 8) { b.StoreReg64(1, 0); b.AddImm(1, 8); }
// timeout_ms @ [rbp-56+40] = [rbp-16]
// timeout_ms @ [rbp-56+36] = [rbp-20]
b.LoadRbp(0, -72);
b.LeaRbp(1, -16); b.StoreReg32(1, 0);
b.LeaRbp(1, -20); b.StoreReg32(1, 0);
// ioctl(gui_fd, WAIT_WINDOW_EVENT, &wait)
b.MovImm64BssRef(7, "gui_fd"); b.LoadReg32(7, 7);
b.MovImm64(6, LEONOS_GUI_IOCTL_WAIT_WINDOW_EVENT);
b.LeaRbp(2, -56);
b.MovEax(SYS_ioctl); b.Int80();
b.MovImm64BssRef(7, "gui_fd"); // rdi = &gui_fd
b.LoadReg32(7, 0); // rdi = gui_fd
b.MovImm64(6, LEONOS_GUI_IOCTL_WAIT_WINDOW_EVENT); // rsi = request
b.LeaRbp(2, -56); // rdx = &wait
b.MovEax(SYS_ioctl); b.Syscall(); // rax = result
b.Test(0, 0);
b.Jle(noEvent); // rax <= 0 → 无事件(含错误),防止死循环
// 翻译事件(event 在 [rbp-56],ev 在 [rbp-64]
b.LoadRbp(7, -64); // rdi = ev
b.LeaRbp(10, -56); // r10 = &event
GenGuiTranslateEvent(b, 7, 10);
b.MovImm64(0, 1); // return 1
b.Leave(); b.Ret();
b.Mark(noEvent);
b.LoadRbp(7, -64); // rdi = ev
b.Xor(0, 0); b.StoreReg32(7, 0); // ev->type = 0
b.Xor(0, 0); // return 0
b.Leave(); b.Ret();
}
// int gui_window_destroy(int win)
private static void GenGuiWindowDestroy(Rt b)
{
// 参数:rdi=win(7)
// ioctl(gui_fd, DESTROY_WINDOW, &win_id);win_id 存于 [rbp-8]
b.PushRbp(); b.MovRbpRsp(); b.SubRsp(16);
b.StoreRbp(-8, 7); // [rbp-8] = winStoreRbp: mov [rbp+disp], r64
b.MovImm64BssRef(7, "gui_fd"); b.LoadReg32(7, 7); // rdi = gui_fd
b.MovImm64(6, LEONOS_GUI_IOCTL_DESTROY_WINDOW); // rsi = request
b.LeaRbp(2, -8); // rdx = &win_id
b.MovEax(SYS_ioctl); b.Int80();
// 与 libc.a 一致:ioctl(gui_fd, DESTROY_WINDOW, win_value) — window_id 作为值传递,非指针
b.PushRbp(); b.MovRbpRsp();
b.Mov(2, 7); // rdx = win(值,非指针
b.MovImm64BssRef(7, "gui_fd"); // rdi = &gui_fd
b.LoadReg32(7, 0); // rdi = gui_fd
b.MovImm64(6, LEONOS_GUI_IOCTL_DESTROY_WINDOW); // rsi = request
b.MovEax(SYS_ioctl); b.Syscall();
b.Xor(0, 0); // return 0
b.Leave(); b.Ret();
}
// int gui_cleanup(void) — 关闭 GUI 设备。
// int gui_cleanup(void) — 关闭 GUI 设备 fd
private static void GenGuiCleanup(Rt b)
{
b.PushRbp(); b.MovRbpRsp(); b.SubRsp(16);
b.MovImm64BssRef(7, "gui_fd"); b.LoadReg32(7, 7); // rdi = gui_fd
b.Test(7, 7);
int skip = b.Lbl();
b.Je(skip); // gui_fd == 0 → skip
b.MovEax(SYS_close); b.Int80();
// gui_fd = 0
b.MovImm64BssRef(7, "gui_fd"); b.Xor(0, 0); b.StoreReg32(7, 0);
b.Mark(skip);
b.PushRbp(); b.MovRbpRsp();
// close(gui_fd)
b.MovImm64BssRef(7, "gui_fd"); // rdi = &gui_fd
b.LoadReg32(7, 0); // rdi = gui_fd
b.MovEax(SYS_close); b.Syscall();
b.Xor(0, 0); // return 0
b.Leave(); b.Ret();
}
// ============ 函数实现 ============
private static void GenExit(Rt b) { b.MovEax(SYS_exit); b.Int80(); b.Ret(); }
// int open(const char *path, int flags, ...) — rdi=path, rsi=flags, rdx=mode
private static void GenOpen(Rt b)
{
b.MovEax(SYS_open); b.Syscall(); b.Ret();
}
private static void GenAbort(Rt b) { b.MovEdi(1); b.MovEax(SYS_exit); b.Int80(); b.Ret(); }
// int close(int fd) — rdi=fd
private static void GenClose(Rt b)
{
b.MovEax(SYS_close); b.Syscall(); b.Ret();
}
private static void GenExit(Rt b) { b.MovEax(SYS_exit); b.Syscall(); b.Ret(); }
private static void GenAbort(Rt b) { b.MovEdi(1); b.MovEax(SYS_exit); b.Syscall(); b.Ret(); }
private static void GenPutchar(Rt b)
{
@@ -384,7 +545,7 @@ public static class Los4Runtime
b.MovEdi(1); // fd=stdout
b.Emit(0x48, 0x8D, 0x34, 0x24); // lea rsi, [rsp]
b.MovEdx(1);
b.MovEax(SYS_write); b.Int80();
b.MovEax(SYS_write); b.Syscall();
b.Emit(0x40, 0x0F, 0xB6, 0xC7); // movzx eax, dil
b.Leave(); b.Ret();
}
@@ -405,12 +566,12 @@ public static class Los4Runtime
b.Mov(2, 1); // rdx=len
b.PopR(6); // rsi=s
b.MovEdi(1); // stdout
b.MovEax(SYS_write); b.Int80();
b.MovEax(SYS_write); b.Syscall();
// write '\n'
b.Push8((byte)'\n');
b.Mov(6, 4); // rsi=rsp
b.MovEdx(1); b.MovEdi(1);
b.MovEax(SYS_write); b.Int80();
b.MovEax(SYS_write); b.Syscall();
b.AddRsp(8);
b.Xor(0, 0);
b.PopRbp(); b.Ret();
@@ -526,7 +687,7 @@ public static class Los4Runtime
b.Mov(2, 12); b.Sub(2, 13); // rdx = len
b.Mov(6, 13); // rsi = buf
b.MovEdi(1);
b.MovEax(SYS_write); b.Int80();
b.MovEax(SYS_write); b.Syscall();
b.Mov(0, 12); b.Sub(0, 13); // rax = len
b.AddRsp(0x438);
b.PopR(15); b.PopR(14); b.PopR(13); b.PopR(12); b.PopR(3);
@@ -705,20 +866,34 @@ public static class Los4Runtime
private static void GenMalloc(Rt b)
{
// void *malloc(size_t size) — rdi = size
// mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
// BSS bump pool allocationlos4 模拟器无 mmap,用 BSS 静态池)
// heap_ptr 初始为 0,表示尚未初始化;首次调用时初始化为 heap_pool 基址
b.PushRbp(); b.MovRbpRsp();
b.AddImm(7, 15); b.AndImm(7, -16); // 对齐 size 到 16 字节
b.Mov(6, 7); // rsi = length
b.XorEdiEdi(); // rdi = addr = 0
b.MovEdx(PROT_READ | PROT_WRITE); // rdx = prot = 3
b.MovImm64(10, MAP_PRIVATE | MAP_ANONYMOUS); // r10 = flags = 0x22
b.MovImm64(8, -1); // r8 = fd = -1
b.Xor(9, 9); // r9 = offset = 0
b.MovEax(SYS_mmap); b.Int80(); // rax = ptr
// 读取 heap_ptr,若为 0 则初始化为 heap_pool
b.MovImm64BssRef(0, "heap_ptr"); // rax = &heap_ptr
b.LoadReg64(0, 0); // rax = *heap_ptr (当前偏移)
b.Test(0, 0); // 检查是否为 0
int skipInit = b.Lbl();
b.Jne(skipInit);
// 初始化:heap_ptr = &heap_pool(直接用地址,不能 LoadReg64 因为 BSS 初值为 0
b.MovImm64BssRef(0, "heap_pool"); // rax = &heap_pool(地址本身)
b.MovImm64BssRef(2, "heap_ptr"); // rdx = &heap_ptr
b.StoreReg64(2, 0); // *heap_ptr = &heap_pool
b.Mark(skipInit);
// 分配:新指针 = heap_ptr + size
b.MovImm64BssRef(2, "heap_ptr"); // rdx = &heap_ptr
b.LoadReg64(0, 2); // rax = *heap_ptr (当前位置)
b.Mov(1, 7); // rcx = size
b.Add(0, 1); // rax += size (新分配地址)
b.StoreReg64(2, 0); // *heap_ptr = 新位置
// rax = 原始指针 = 新位置 - size
b.Mov(2, 7); // rdx = size
b.Sub(0, 2); // rax -= size → rax = 原始指针
b.PopRbp(); b.Ret();
}
private static void GenFree(Rt b) { b.Ret(); } // mmap 内存由内核管理,free 为空操作
private static void GenFree(Rt b) { b.Ret(); } // bump pool 无需释放
private static void GenCalloc(Rt b)
{
@@ -727,16 +902,11 @@ public static class Los4Runtime
b.Imul(7, 6); // rdi = total = nmemb * size
b.AddImm(7, 15); b.AndImm(7, -16); // 对齐到 16 字节
b.PushR(7); // 保存 total 供 memset 使用
b.Mov(6, 7); // rsi = length = total
b.XorEdiEdi(); // rdi = addr = 0
b.MovEdx(PROT_READ | PROT_WRITE); // rdx = prot
b.MovImm64(10, MAP_PRIVATE | MAP_ANONYMOUS); // r10 = flags
b.MovImm64(8, -1); // r8 = fd = -1
b.Xor(9, 9); // r9 = offset = 0
b.MovEax(SYS_mmap); b.Int80(); // rax = ptr
// 用 malloc 分配(通过调回 malloc 函数)
b.CallName("malloc");
// memset(ptr, 0, total)
b.PopR(2); // rdx = total
b.Mov(7, 0); // rdi = ptr
b.Mov(7, 0); // rdi = ptr (rax)
b.Xor(0, 0); // al = 0
b.PushR(0); // 保存 ptr
int loop = b.Lbl(), done = b.Lbl();
@@ -755,7 +925,7 @@ public static class Los4Runtime
b.MovEdi(0); // stdin
b.Emit(0x48, 0x8D, 0x34, 0x24); // lea rsi, [rsp]
b.MovEdx(1);
b.MovEax(SYS_read); b.Int80();
b.MovEax(SYS_read); b.Syscall();
b.Test(0, 0);
int eof = b.Lbl(), ret = b.Lbl();
b.Je(eof);
@@ -778,7 +948,7 @@ public static class Los4Runtime
b.Inc(6); b.Inc(1); b.Jmp(loop);
b.Mark(done);
b.Mov(2, 1); b.PopR(6);
b.MovEdi(1); b.MovEax(SYS_write); b.Int80();
b.MovEdi(1); b.MovEax(SYS_write); b.Syscall();
b.Xor(0, 0);
b.PopRbp(); b.Ret();
}
@@ -903,6 +1073,10 @@ internal sealed class Rt
/// 由 ElfWriterLos4 在段布局完成后修补为字符串的真实虚拟地址。
internal readonly List<(int off, string content)> RdataRefs = new();
/// 运行时代码中对 .rodata 二进制数据的绝对地址引用:(代码内偏移, 数据)。
/// 由 ElfWriterLos4 在段布局完成后将数据追加到 rodata 并修补为真实虚拟地址。
internal readonly List<(int off, byte[] data)> RdataBinRefs = new();
/// 运行时持久状态(BSS 全局):(代码内偏移, 全局名, 全局在运行时 BSS 区内偏移)。
/// 由 ElfWriterLos4 在段布局完成后修补为 BSS 区的真实虚拟地址。
internal readonly List<(int off, string name, int bssOff)> BssRefs = new();
@@ -983,7 +1157,7 @@ internal sealed class Rt
// ---- 基础 ----
internal void Ret() => _code.Add(0xC3);
internal void Int80() { _code.Add(0xCD); _code.Add(0x80); }
internal void Syscall() { _code.Add(0xCD); _code.Add(0x80); } // int 0x80 (LeonOS 4 使用 int 0x80 而非 syscall)
internal void Leave() => _code.Add(0xC9);
internal void PushRbp() => _code.Add(0x55);
internal void PopRbp() => _code.Add(0x5D);
@@ -1036,6 +1210,18 @@ internal sealed class Rt
for (int i = 0; i < 8; i++) _code.Add(0);
}
/// mov r64, &bin —— 发射 REX + 操作码 + 8 字节占位 0,并记录二进制数据引用。
/// ElfWriterLos4 在确定 .rodata 布局后将数据追加到 rodata 并回填真实虚拟地址。
internal void MovImm64RdataBinRef(int reg, byte[] data)
{
byte rex = 0x48; // REX.W
if (reg >= 8) rex |= 0x01; // REX.B
_code.Add(rex);
_code.Add((byte)(0xB8 + (reg & 7)));
RdataBinRefs.Add((_code.Count, data)); // 记录 8 字节占位起始偏移
for (int i = 0; i < 8; i++) _code.Add(0);
}
// ---- xor r64, r64 ----
internal void Xor(int dst, int src) { _code.Add(RexRR(src, dst)); _code.Add(0x31); _code.Add((byte)(0xC0 | ((src & 7) << 3) | (dst & 7))); }
internal void XorEdiEdi() => Emit(0x48, 0x31, 0xFF);
@@ -1147,10 +1147,15 @@ public sealed class X64CodeGenerator : ICodeGenerator
}
}
int outBytes = AlignUp(shadow + nStack * 8 + structCopyBytes, 16);
// 寄存器参数溢出槽:求值每个参数时先存到 [rsp+slot],最后批量载入寄存器。
// Win64 的 shadow space32 字节)可容纳 4 个溢出槽;SysV 无 shadow,
// 必须单独分配 regCount*8 字节,否则溢出槽会覆盖调用者的栈临时量。
int spillBytes = regCount * 8;
int argBase = Math.Max(shadow, spillBytes); // 栈参数起始偏移
int outBytes = AlignUp(argBase + nStack * 8 + structCopyBytes, 16);
if (outBytes != 0) _e.SubImm(Rsp, outBytes);
int copyBase = shadow + nStack * 8;
int copyBase = argBase + nStack * 8;
// 先复制结构体内容到副本区(求值顺序:结构体在标量之前,避免标量寄存器被 CopyBytes 破坏)
foreach (var kv in structOff)
@@ -1169,7 +1174,7 @@ public sealed class X64CodeGenerator : ICodeGenerator
_e.Lea(Rax, Mem.BaseDisp(Rsp, copyBase + structOff[i]));
else
GenValue(args[i]); // Rax = arg
int slot = i < regCount ? i * 8 : shadow + (i - regCount) * 8;
int slot = i < regCount ? i * 8 : argBase + (i - regCount) * 8;
_e.Store64(Mem.BaseDisp(Rsp, slot), Rax);
}
// 把寄存器参数从溢出槽载入对应寄存器
+6 -1
查看文件
@@ -675,12 +675,17 @@ public sealed class Parser
case TokenKind.KwSizeof:
{
var r = Peek().Range; _i++;
if (Check(TokenKind.LParen) && IsTypeName(Peek()))
// sizeof(type)'(' 紧跟类型名。先用 Peek 判定(不消费 '('),
// 否则 sizeof(expr) 路径会因 '(' 已被消费而漏吃匹配的 ')',
// 导致后续语句多出一个 ')'(“期望 ;,但遇到 ')'”)。
if (Peek().Kind == TokenKind.LParen && IsTypeName(Peek(1)))
{
_i++; // consume '('
var t = ParseTypeName();
Expect(TokenKind.RParen, ")");
return new SizeofExpr(null, t) { Range = r };
}
// sizeof expr / sizeof(expr):括号由一元/初等表达式自行消费。
var e = ParseUnary();
return new SizeofExpr(e, null) { Range = r };
}
+1 -1
查看文件
@@ -14,7 +14,7 @@
<!-- 版本通道:release | beta | alpha,可经 -p:BuildChannel=beta 覆盖 -->
<BuildChannel Condition="'$(BuildChannel)' == ''">release</BuildChannel>
<BuildChannel Condition="'$(BuildChannel)' != 'release' And '$(BuildChannel)' != 'beta' And '$(BuildChannel)' != 'alpha'">release</BuildChannel>
<VersionPrefix>0.1.0</VersionPrefix>
<VersionPrefix>0.1.1</VersionPrefix>
<Version Condition="'$(BuildChannel)' == 'release'">$(VersionPrefix)</Version>
<Version Condition="'$(BuildChannel)' != 'release'">$(VersionPrefix)-$(BuildChannel)</Version>
<FileVersion>0.1.0.0</FileVersion>
+189 -20
查看文件
@@ -124,6 +124,7 @@ extern unsigned int SetBkColor(void *, unsigned int);
extern int TextOutA(void *, int, int, const char *, int);
extern int InvalidateRect(void *, void *, int);
extern int DwmSetWindowAttribute(void *, int, void *, int);
extern void *CreateSolidBrush(unsigned int color);
/* ---- Win32 常量 ---- */
#define WS_OVERLAPPEDWINDOW 0x00CF0000
@@ -173,9 +174,21 @@ static long long paze_wndproc(void *h, unsigned int msg, unsigned long long w, l
void *dc = BeginPaint(h, &ps);
SetTextColor(dc, gui_fg);
SetBkColor(dc, gui_bg);
int len = 0;
while (gui_text[len]) len++;
TextOutA(dc, gui_text_x, gui_text_y, gui_text, len);
/* 逐行绘制(处理 \n 换行)*/
int line = 0;
int start = 0;
int i = 0;
while (gui_text[i]) {
if (gui_text[i] == '\n') {
if (i > start)
TextOutA(dc, gui_text_x, gui_text_y + line * 18, gui_text + start, i - start);
line++;
start = i + 1;
}
i++;
}
if (i > start)
TextOutA(dc, gui_text_x, gui_text_y + line * 18, gui_text + start, i - start);
EndPaint(h, &ps);
return 0;
}
@@ -192,14 +205,14 @@ int gui_init(void) {
memset(&wc, 0, sizeof(struct paze_wc));
wc.style = 3; /* CS_HREDRAW | CS_VREDRAW */
wc.wndproc = paze_wndproc;
wc.hbrBackground = 6; /* COLOR_WINDOW + 1 */
wc.hbrBackground = CreateSolidBrush(0xFFFFFF); /* 显式白色背景,不依赖系统主题色 */
wc.className = gui_class_name;
if (RegisterClassA(&wc) == 0) return -1;
gui_class_registered = 1;
return 0;
}
int gui_window_create(const char *title, int width, int height) {
int gui_window_create(const char *title, const char *text, int width, int height) {
if (gui_init() < 0) return -1;
gui_hwnd = CreateWindowExA(0, gui_class_name, title, WS_OVERLAPPEDWINDOW,
100, 100, width, height, 0, 0, 0, 0);
@@ -211,7 +224,12 @@ int gui_window_create(const char *title, int width, int height) {
DwmSetWindowAttribute(gui_hwnd, 20, &dark, 4);
gui_fg = 0;
gui_bg = 0xFFFFFF;
gui_text[0] = 0;
gui_text_x = 20;
gui_text_y = 40;
/* 存储初始文本 */
int i = 0;
while (text && text[i] && i < 1023) { gui_text[i] = text[i]; i++; }
gui_text[i] = 0;
ShowWindow(gui_hwnd, SW_SHOW);
UpdateWindow(gui_hwnd);
return 0;
@@ -349,7 +367,7 @@ int gui_init(void) {
return 0;
}
int gui_window_create(const char *title, int width, int height) {
int gui_window_create(const char *title, const char *text, int width, int height) {
if (gui_init() < 0) return -1;
unsigned long root = XRootWindow(gui_display, gui_screen);
unsigned long bg = XWhitePixel(gui_display, gui_screen);
@@ -365,6 +383,14 @@ int gui_window_create(const char *title, int width, int height) {
}
XMapWindow(gui_display, gui_window);
XFlush(gui_display);
/* 绘制初始文本 */
if (text) {
XSetForeground(gui_display, gui_gc, 0);
int len = 0;
while (text[len]) len++;
XDrawString(gui_display, gui_window, gui_gc, 10, 30, text, len);
XFlush(gui_display);
}
return 0;
}
@@ -540,7 +566,7 @@ int gui_init(void) {
return 0;
}
int gui_window_create(const char *title, int width, int height) {
int gui_window_create(const char *title, const char *text, int width, int height) {
if (gui_init() < 0) return -1;
void *winCls = objc_getClass("NSWindow");
if (!winCls) return -1;
@@ -569,6 +595,11 @@ int gui_window_create(const char *title, int width, int height) {
tv = (void *)paze_mac_send_rect(tv, sel_initWithFrame, tvRect, 0, 0, 0);
gui_textview = tv;
objc_msgSend(win, sel_setContentView, tv);
/* 设置初始文本 */
if (text) {
void *textStr = (void *)objc_msgSend(strCls, sel_stringWithUTF8String, text);
objc_msgSend(tv, sel_setString, textStr);
}
objc_msgSend(win, sel_makeKeyAndOrderFront, 0);
return 0;
}
@@ -623,20 +654,158 @@ int gui_cleanup(void) {
}
#elif defined(__leonos__)
/* Los4 GUI — 阶段5 实现(Los4Runtime 静态生成 + ioctl*/
int gui_init(void);
int gui_window_create(const char *title, int width, int height);
int gui_window_text(int win, int x, int y, const char *text, unsigned int fg, unsigned int bg);
int gui_window_present(int win);
int gui_event_poll(struct gui_event *ev);
int gui_event_wait(struct gui_event *ev, int timeout_ms);
int gui_window_destroy(int win);
int gui_cleanup(void);
/* Los4 GUI — C 实现:与运行时 GenGui* 完全一致的 ioctl 路径 */
/* 运行时底层辅助(Los4Runtime 静态生成)*/
extern int paze_ioctl(int fd, unsigned long req, void *arg);
extern int open(const char *path, int flags, ...);
/* Los4 GUI ioctl 码(来自 leonos/gui.h*/
#define PAZE_LOS4_CREATE_WINDOW 0x4c475743UL
#define PAZE_LOS4_FB_FILL 0x4c464246UL
#define PAZE_LOS4_FB_TEXT 0x4c464254UL
#define PAZE_LOS4_WINDOW_EVENT 0x4c475745UL
#define PAZE_LOS4_WAIT_EVENT 0x4c475457UL
#define PAZE_LOS4_DESTROY_WINDOW 0x4c475744UL
/* Los4 应用事件类型 */
#define PAZE_LOS4_EV_CLOSE 1
#define PAZE_LOS4_EV_MOUSE_BUTTON 6
#define PAZE_LOS4_EV_KEY_DOWN 7
/* GUI ioctl 结构体(布局与 leonos/gui.h 一致)*/
struct paze_los4_create {
unsigned int width;
unsigned int height;
const char *title;
const char *text;
unsigned int flags;
};
struct paze_los4_fb_text {
unsigned int x;
unsigned int y;
unsigned int fg;
unsigned int bg;
const char *text;
};
struct paze_los4_event {
unsigned int window_id;
unsigned int type;
int x;
int y;
int dx;
int dy;
unsigned int width;
unsigned int height;
unsigned char buttons;
unsigned char keycode;
unsigned char pressed;
unsigned char reserved;
};
struct paze_los4_wait {
struct paze_los4_event event;
unsigned int timeout_ms;
};
/* GUI 状态 */
static int gui_fd;
static int gui_win_id;
static int gui_win_w;
static int gui_win_h;
int gui_init(void) {
/* 打开 GUI 设备(与 GenGuiInit 一致)*/
int fd = open("0:/dev/leonos_gui", 2); /* O_RDWR = 2 */
if (fd < 0) return -1;
gui_fd = fd;
return 0;
}
int gui_window_create(const char *title, const char *text, int width, int height) {
struct paze_los4_create gc;
gc.width = (unsigned int)width;
gc.height = (unsigned int)height;
gc.title = title;
gc.text = text;
gc.flags = 0;
int wid = paze_ioctl(gui_fd, PAZE_LOS4_CREATE_WINDOW, &gc);
if (wid <= 0) return -1;
gui_win_id = wid;
gui_win_w = width;
gui_win_h = height;
/* 填充白色背景 + 黑色文字(与 GenGuiWindowText 一致的 FB_TEXT 路径)*/
paze_ioctl(gui_fd, PAZE_LOS4_FB_FILL, (void*)(unsigned long)0xFFFFFFFF);
struct paze_los4_fb_text ft;
ft.x = 10;
ft.y = 10;
ft.fg = 0xFF000000; /* 黑色 */
ft.bg = 0xFFFFFFFF; /* 白色 */
ft.text = text;
paze_ioctl(gui_fd, PAZE_LOS4_FB_TEXT, &ft);
return 0;
}
int gui_window_text(int win, int x, int y, const char *text, unsigned int fg, unsigned int bg) {
struct paze_los4_fb_text ft;
ft.x = (unsigned int)x;
ft.y = (unsigned int)y;
ft.fg = fg;
ft.bg = bg;
ft.text = text;
paze_ioctl(gui_fd, PAZE_LOS4_FB_TEXT, &ft);
return 0;
}
int gui_window_present(int win) { return 0; } /* FB_TEXT 直接渲染,无需 present */
static void paze_los4_translate(struct paze_los4_event *e, struct gui_event *ev) {
ev->window_id = (int)e->window_id;
ev->type = 0;
if (e->type == PAZE_LOS4_EV_CLOSE) {
ev->type = 1;
} else if (e->type == PAZE_LOS4_EV_KEY_DOWN) {
ev->type = 2;
ev->key = (int)e->keycode;
} else if (e->type == PAZE_LOS4_EV_MOUSE_BUTTON) {
ev->type = 3;
ev->mouse_x = e->x;
ev->mouse_y = e->y;
ev->button = (int)e->buttons;
}
}
int gui_event_poll(struct gui_event *ev) {
struct paze_los4_event e;
memset(&e, 0, sizeof(e));
int r = paze_ioctl(gui_fd, PAZE_LOS4_WINDOW_EVENT, &e);
if (r <= 0) { ev->type = 0; return 0; }
paze_los4_translate(&e, ev);
return 1;
}
int gui_event_wait(struct gui_event *ev, int timeout_ms) {
struct paze_los4_wait w;
memset(&w, 0, sizeof(w));
w.timeout_ms = (unsigned int)timeout_ms;
int r = paze_ioctl(gui_fd, PAZE_LOS4_WAIT_EVENT, &w);
if (r <= 0) { ev->type = 0; return 0; }
paze_los4_translate(&w.event, ev);
return 1;
}
int gui_window_destroy(int win) {
union { void *p; long l; } u;
u.l = (long)win;
paze_ioctl(gui_fd, PAZE_LOS4_DESTROY_WINDOW, u.p);
return 0;
}
int gui_cleanup(void) { return 0; }
#else
/* 不支持 GUI 的平台 — 桩实现 */
int gui_init(void) { return -1; }
int gui_window_create(const char *title, int width, int height) { return -1; }
int gui_window_create(const char *title, const char *text, int width, int height) { return -1; }
int gui_window_text(int win, int x, int y, const char *text, unsigned int fg, unsigned int bg) { return -1; }
int gui_window_present(int win) { return -1; }
int gui_event_poll(struct gui_event *ev) { ev->type = 0; return 0; }
@@ -664,8 +833,8 @@ int gui_cleanup(void) { return -1; }
or "DefWindowProcA" or "DestroyWindow" or "PostQuitMessage"
or "BeginPaint" or "EndPaint" or "GetDC" or "ReleaseDC" or "InvalidateRect"
or "SetWindowTextA" => "user32.dll",
// gdi32.dll — 文本绘制、颜色
"SetTextColor" or "SetBkColor" or "TextOutA" => "gdi32.dll",
// gdi32.dll — 文本绘制、颜色、画刷
"SetTextColor" or "SetBkColor" or "TextOutA" or "CreateSolidBrush" => "gdi32.dll",
// dwmapi.dll — Win11 DWM 圆角/暗色模式
"DwmSetWindowAttribute" => "dwmapi.dll",
_ => "msvcrt.dll"
+2 -2
查看文件
@@ -45,7 +45,7 @@ public static class StartupStubs
}
/// <summary>LeonOS 4 _startcall main;mov edi,eax;mov eax,60;int 0x80。
/// LeonOS 4 使用 int 0x80(非 syscall 指令)进行系统调用,寄存器约定同 Linux x86_64。</summary>
/// LeonOS 4 使用 int 0x80 指令(0xCD 0x80,寄存器约定同 Linux x86_64。</summary>
public static (byte[] code, List<StubFixup> fixups) Los4(bool hasArgcArgv)
{
var b = new List<byte>();
@@ -59,7 +59,7 @@ public static class StartupStubs
b.Add(0xE8); fx.Add(new StubFixup(b.Count, FixupKind.Rel32, "main")); b.AddRange(new byte[4]); // call main
b.AddRange(new byte[] { 0x89, 0xC7 }); // mov edi, eax
b.AddRange(new byte[] { 0xB8, 0x3C, 0x00, 0x00, 0x00 }); // mov eax, 60 (SYS_exit)
b.AddRange(new byte[] { 0xCD, 0x80 }); // int 0x80
b.AddRange(new byte[] { 0xCD, 0x80 }); // int 0x80 (LeonOS 4 使用 int 0x80)
return (b.ToArray(), fx);
}
@@ -1,12 +1,17 @@
<Project Sdk="WixToolset.Sdk/6.0.2">
<PropertyGroup>
<OutputName>PazeE-0.1.0-alpha-win-x64</OutputName>
<!-- BundleCulture: zh-cn(默认,无后缀) / en-us / zh-tw。用 -p:BundleCulture=en-us 切换 -->
<BundleCulture Condition="'$(BundleCulture)' == ''">zh-cn</BundleCulture>
<CultureSuffix Condition="'$(BundleCulture)' == 'zh-cn'"></CultureSuffix>
<CultureSuffix Condition="'$(BundleCulture)' != 'zh-cn'">-$(BundleCulture)</CultureSuffix>
<OutputName>PazeE-0.1.1-alpha-win-x64$(CultureSuffix)</OutputName>
<OutputType>Bundle</OutputType>
<OutputPath>..\..\publish\0.1.0-alpha\installer\</OutputPath>
<DefineConstants>PazeEVersion=0.1.0-alpha;MsiVersion=0.1.0;MsiTargetPath=$(MSBuildProjectDirectory)\obj\Release\zh-cn\PazeE-0.1.0-alpha-win-x64.msi</DefineConstants>
<Cultures>zh-cn</Cultures>
<DefaultCulture>zh-cn</DefaultCulture>
<OutputPath>..\..\publish\0.1.1-alpha\installer\</OutputPath>
<!-- 引用对应 culture 的单语言 MSIzh-cn/en-us/zh-tw 子目录中的原始 MSI -->
<DefineConstants>PazeEVersion=0.1.1-alpha;MsiVersion=0.1.1;MsiTargetPath=$(MSBuildProjectDirectory)\obj\Release\$(BundleCulture)\PazeE-0.1.1-alpha-win-x64.msi</DefineConstants>
<Cultures>$(BundleCulture)</Cultures>
<DefaultCulture>$(BundleCulture)</DefaultCulture>
<!-- 两个项目共享同一目录:排除 Product.wxs 和 .wxl 本地化文件(由 MSI 项目处理) -->
<DefaultItemExcludes>$(DefaultItemExcludes);Product.wxs;*.wxl</DefaultItemExcludes>
</PropertyGroup>
@@ -1,14 +1,14 @@
<Project Sdk="WixToolset.Sdk/6.0.2">
<PropertyGroup>
<OutputName>PazeE-0.1.0-alpha-win-x64</OutputName>
<OutputName>PazeE-0.1.1-alpha-win-x64</OutputName>
<OutputType>Package</OutputType>
<!-- MSI 作为中间产物输出到 obj(不单独发布,仅供 Bundle 内嵌) -->
<OutputPath>obj\Release\</OutputPath>
<!-- MSBuild 属性(供 HarvestDirectory 引用) -->
<PublishBinDir>..\..\publish\0.1.0-alpha\bin</PublishBinDir>
<PublishBinDir>..\..\publish\0.1.1-alpha\bin</PublishBinDir>
<!-- 同时作为 WiX 预处理器变量传入 .wxs -->
<DefineConstants>PazeEVersion=0.1.0-alpha;MsiVersion=0.1.0;PublishBinDir=$(PublishBinDir)</DefineConstants>
<DefineConstants>PazeEVersion=0.1.1-alpha;MsiVersion=0.1.1;PublishBinDir=$(PublishBinDir)</DefineConstants>
<!-- x64 平台:使 heat 生成的组件标记为 64 位,匹配 ProgramFiles64Folder -->
<Platform>x64</Platform>
<!-- 抑制 .NET 自包含运行时常见的 ICE 校验警告 -->
@@ -17,7 +17,7 @@
<!-- 两个项目共享同一目录:排除 Bundle.wxs,SDK 自动包含 Product.wxs + heat 生成文件 -->
<DefaultItemExcludes>$(DefaultItemExcludes);Bundle.wxs</DefaultItemExcludes>
<!-- MSI 输出目录(同时发布 MSI 到 installer 目录,与 .exe 并列) -->
<PublishDir>..\..\publish\0.1.0-alpha\installer\</PublishDir>
<PublishDir>..\..\publish\0.1.1-alpha\installer\</PublishDir>
<!-- 多语言构建:简体中文(默认) + English + 繁體中文 -->
<Cultures>zh-cn;en-us;zh-tw</Cultures>
<DefaultCulture>zh-cn</DefaultCulture>
@@ -52,11 +52,47 @@
</HarvestDirectory>
</ItemGroup>
<!-- 构建后复制 MSI 到 publish 目录(与 Bundle .exe 并列 -->
<!-- 多语言构建:每个 culture 生成独立 MSI,复制默认语言(zh-cn)到 publish -->
<Target Name="PublishMsi" AfterTargets="Build" Condition="'$(PublishDir)' != ''">
<!-- 生成语言 transforms 并嵌入到多语言 MSI(独立文件,不影响原始 zh-cn MSI 供 Bundle 引用 -->
<!-- 流程:Build 后 → 复制 zh-cn MSI 为多语言 MSI → 生成 .mst → 嵌入 transforms + 改 Summary Template -->
<!-- 结果:obj\Release\<name>.msi = 多语言 MSIpublish 分发);obj\Release\zh-cn\<name>.msi = 单语言(Bundle 引用) -->
<Target Name="EmbedLanguageTransforms" AfterTargets="Build" BeforeTargets="PublishMsi">
<PropertyGroup>
<WixExe Condition="'$(WixExe)' == '' And '$(PkgWixToolset_Sdk)' != ''">$([System.IO.Path]::Combine('$(PkgWixToolset_Sdk)', 'tools\net472\x64\wix.exe'))</WixExe>
<WixExe Condition="'$(WixExe)' == ''">$(USERPROFILE)\.nuget\packages\wixtoolset.sdk\6.0.2\tools\net472\x64\wix.exe</WixExe>
<ObjOut>$(OutputPath)</ObjOut>
<MsiFile>$(OutputName).msi</MsiFile>
<ZhCnMsi>$(ObjOut)zh-cn\$(MsiFile)</ZhCnMsi>
<EnUsMsi>$(ObjOut)en-us\$(MsiFile)</EnUsMsi>
<ZhTwMsi>$(ObjOut)zh-tw\$(MsiFile)</ZhTwMsi>
<MultiLangMsi>$(ObjOut)$(MsiFile)</MultiLangMsi>
<EnMst>$(ObjOut)en-us.mst</EnMst>
<TwMst>$(ObjOut)zh-tw.mst</TwMst>
<EmbedScript>$(MSBuildProjectDirectory)\embed_lang.ps1</EmbedScript>
<PsExe>$(SystemRoot)\System32\WindowsPowerShell\v1.0\powershell.exe</PsExe>
</PropertyGroup>
<!-- 复制 zh-cn MSI 为多语言版本(原始 zh-cn MSI 保持单语言供 Bundle 引用) -->
<Copy SourceFiles="$(ZhCnMsi)" DestinationFiles="$(MultiLangMsi)" SkipUnchangedFiles="false" />
<!-- 生成 en-us 语言 transform(相对于 zh-cn 基础 MSI -->
<Exec Command='"$(WixExe)" msi transform -t language "$(ZhCnMsi)" "$(EnUsMsi)" -out "$(EnMst)"'
ConsoleToMSBuild="true" />
<!-- 生成 zh-tw 语言 transform -->
<Exec Command='"$(WixExe)" msi transform -t language "$(ZhCnMsi)" "$(ZhTwMsi)" -out "$(TwMst)"'
ConsoleToMSBuild="true" />
<!-- 嵌入 transforms 到多语言 MSIstorage '1033'=en-us, '1028'=zh-tw;Summary Template=x64;2052,1033,1028 -->
<Exec Command='"$(PsExe)" -ExecutionPolicy Bypass -File "$(EmbedScript)" -MsiPath "$(MultiLangMsi)" -EnMst "$(EnMst)" -TwMst "$(TwMst)"'
ConsoleToMSBuild="true" />
<Message Text="Multi-language MSI built: $(MultiLangMsi) (zh-cn + en-us + zh-tw, auto language selection)" Importance="high" />
</Target>
<!-- 构建后复制多语言 MSI 到 publish 目录(与 Bundle .exe 并列) -->
<Target Name="PublishMsi" AfterTargets="EmbedLanguageTransforms" Condition="'$(PublishDir)' != ''">
<ItemGroup>
<_MsiFiles Include="$(OutputPath)$(DefaultCulture)\*.msi" />
<_MsiFiles Include="$(OutputPath)$(OutputName).msi" />
</ItemGroup>
<Copy SourceFiles="@(_MsiFiles)"
DestinationFolder="$(MSBuildProjectDirectory)\$(PublishDir)"
+3 -3
查看文件
@@ -37,10 +37,10 @@
<!-- 默认语言:简体中文(如果用户未选择) -->
<Property Id="UILanguage" Value="zh-cn" />
<!-- 安装目录:C:\Program Files\PazeE\0.1.0-alpha\ -->
<!-- 安装目录:C:\Program Files\PazeE\0.1.1-alpha\ -->
<StandardDirectory Id="ProgramFiles64Folder">
<Directory Id="PazeEFolder" Name="PazeE">
<Directory Id="INSTALLFOLDER" Name="0.1.0-alpha" />
<Directory Id="INSTALLFOLDER" Name="0.1.1-alpha" />
</Directory>
</StandardDirectory>
@@ -68,7 +68,7 @@
Action="set"
System="yes" />
<RegistryKey Root="HKLM" Key="SOFTWARE\PazeE\0.1.0-alpha">
<RegistryKey Root="HKLM" Key="SOFTWARE\PazeE\0.1.1-alpha">
<RegistryValue Type="string" Name="InstallPath" Value="[INSTALLFOLDER]" />
<RegistryValue Type="string" Name="Version" Value="$(var.PazeEVersion)" />
</RegistryKey>
+103
查看文件
@@ -0,0 +1,103 @@
# embed_lang.ps1 - Embed language transforms into MSI to create a multi-language MSI
# Usage: powershell -File embed_lang.ps1 -MsiPath <zh-cn.msi> -EnMst <en-us.mst> -TwMst <zh-tw.mst>
param(
[Parameter(Mandatory=$true)][string]$MsiPath,
[Parameter(Mandatory=$true)][string]$EnMst,
[Parameter(Mandatory=$true)][string]$TwMst
)
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public static class MsiEmbed {
const int MSIDBOPEN_TRANSACT = 1;
const int MSIDBOPEN_READONLY = 0;
const uint PID_TEMPLATE = 7; // SummaryInformation: Platform;Language
const int VT_LPSTR = 30;
[DllImport("msi.dll", CharSet = CharSet.Unicode)]
static extern uint MsiOpenDatabaseW(string szDatabasePath, int szPersist, out IntPtr phDatabase);
[DllImport("msi.dll", CharSet = CharSet.Unicode)]
static extern uint MsiDatabaseOpenViewW(IntPtr hDatabase, string szQuery, out IntPtr phView);
[DllImport("msi.dll")]
static extern uint MsiViewExecute(IntPtr hView, IntPtr hRecord);
[DllImport("msi.dll")]
static extern uint MsiViewClose(IntPtr hView);
[DllImport("msi.dll")]
static extern uint MsiDatabaseCommit(IntPtr hDatabase);
[DllImport("msi.dll")]
static extern IntPtr MsiCreateRecord(uint cParams);
[DllImport("msi.dll", CharSet = CharSet.Unicode)]
static extern uint MsiRecordSetStringW(IntPtr hRecord, uint iField, string szValue);
[DllImport("msi.dll", CharSet = CharSet.Unicode)]
static extern uint MsiRecordSetStreamW(IntPtr hRecord, uint iField, string szFilePath);
[DllImport("msi.dll", CharSet = CharSet.Unicode)]
static extern uint MsiGetSummaryInformationW(IntPtr hDatabase, string szDatabasePath, uint uiUpdateCount, out IntPtr phSummaryInfo);
[DllImport("msi.dll", CharSet = CharSet.Unicode)]
static extern uint MsiSummaryInfoSetPropertyW(IntPtr hSummaryInfo, uint uiProperty, int uiType, int iValue, IntPtr pftValue, string szValue);
[DllImport("msi.dll")]
static extern uint MsiSummaryInfoPersist(IntPtr hSummaryInfo);
static string Check(uint r, string ctx) {
if (r != 0) throw new Exception("MSI error " + r + " at: " + ctx);
return "OK";
}
public static void Embed(string msiPath, string enMst, string twMst) {
IntPtr hDb;
Check(MsiOpenDatabaseW(msiPath, MSIDBOPEN_TRANSACT, out hDb), "OpenDatabase");
// Ensure _Storages table exists; create if missing
try {
IntPtr hView0;
MsiDatabaseOpenViewW(hDb, "SELECT * FROM `_Storages`", out hView0);
MsiViewExecute(hView0, IntPtr.Zero);
MsiViewClose(hView0);
} catch {
Console.WriteLine("Creating _Storages table...");
IntPtr hCV;
Check(MsiDatabaseOpenViewW(hDb, "CREATE TABLE `_Storages` (`Name` CHAR(255) NOT NULL LOCALIZABLE, `Data` OBJECT NOT NULL PRIMARY KEY `Name`)", out hCV), "OpenView CREATE");
Check(MsiViewExecute(hCV, IntPtr.Zero), "Execute CREATE");
MsiViewClose(hCV);
}
EmbedStorage(hDb, "1033", enMst, "en-us");
EmbedStorage(hDb, "1028", twMst, "zh-tw");
// Update SummaryInformation Template (PID 7 = "Platform;Language") 为多语言
// Windows Installer 运行时根据系统语言自动应用对应 transform不匹配时显示语言选择
IntPtr hSum;
Check(MsiGetSummaryInformationW(hDb, null, 1, out hSum), "GetSummaryInfo");
Check(MsiSummaryInfoSetPropertyW(hSum, PID_TEMPLATE, VT_LPSTR, 0, IntPtr.Zero, "x64;2052,1033,1028"), "SummarySetProperty");
Check(MsiSummaryInfoPersist(hSum), "SummaryPersist");
Check(MsiDatabaseCommit(hDb), "Commit");
Console.WriteLine("Multi-language MSI built: " + msiPath);
}
static void EmbedStorage(IntPtr hDb, string storageName, string mstPath, string label) {
Console.WriteLine("Embedding " + label + " transform as storage '" + storageName + "'...");
IntPtr hView;
Check(MsiDatabaseOpenViewW(hDb, "INSERT INTO `_Storages` (`Name`, `Data`) VALUES (?, ?)", out hView), "OpenView INSERT " + label);
IntPtr hRec = MsiCreateRecord(2);
Check(MsiRecordSetStringW(hRec, 1, storageName), "SetString " + label);
Check(MsiRecordSetStreamW(hRec, 2, mstPath), "SetStream " + label);
Check(MsiViewExecute(hView, hRec), "Execute INSERT " + label);
MsiViewClose(hView);
}
}
"@
[MsiEmbed]::Embed($MsiPath, $EnMst, $TwMst)
+127 -20
查看文件
@@ -1,26 +1,133 @@
/* GUI 测试:创建窗口显示文字,按任意键或关闭窗口退出 */
struct gui_event { int type, key, mouse_x, mouse_y, button, window_id; };
int gui_init(void);
int gui_window_create(const char *title, int width, int height);
int gui_window_text(int win, int x, int y, const char *text, unsigned int fg, unsigned int bg);
int gui_event_wait(struct gui_event *ev, int timeout_ms);
int gui_window_destroy(int win);
/* GUI 测试:PRESENT_WINDOW + 文字渲染(ARGB32 颜色格式)*/
extern int paze_ioctl(int fd, unsigned long req, void *arg);
extern void *malloc(unsigned long size);
extern void memset(void *s, int c, unsigned long n);
int main(void) {
if (gui_init() < 0) return 1;
if (gui_window_create("PazeE GUI Demo", 480, 320) < 0) return 1;
#define CREATE_WINDOW 0x4c475743UL
#define PRESENT_WINDOW 0x4c475046UL
#define WAIT_WINDOW_EVENT 0x4c475457UL
/* 显示文字:黑底绿字 */
gui_window_text(0, 60, 80, "Hello from PazeE!", 0x00FF00, 0x000000);
gui_window_text(0, 60, 120, "Press any key or close to exit", 0xFFFFFF, 0x000000);
struct create { unsigned int width, height; const char *title, *text; unsigned int flags; };
struct present { unsigned int window_id, width, height, stride; unsigned int *pixels; };
struct gui_event ev;
while (1) {
gui_event_wait(&ev, 0);
if (ev.type == 4 || ev.type == 1) break; /* quit or close */
if (ev.type == 2) break; /* key down */
}
struct app_event {
unsigned int window_id;
unsigned int type;
int x, y, dx, dy;
unsigned int width, height;
unsigned char buttons, keycode, pressed;
};
gui_window_destroy(0);
struct wait_event {
struct app_event event;
unsigned int timeout_ms;
};
/* ARGB32 颜色:byte0=A, byte1=R, byte2=G, byte3=B */
#define COL_BLACK 0x000000FFU /* A=FF, R=0, G=0, B=0 */
#define COL_WHITE 0xFFFFFFFFU /* A=FF, R=FF, G=FF, B=FF */
#define COL_RED 0x0000FFFFU /* A=FF, R=FF, G=0, B=0 */
/* 8x16 字体 */
static unsigned char fnt_H[16] = {0x66,0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66};
static unsigned char fnt_e[16] = {0x00,0x00,0x3C,0x66,0x66,0x66,0x7E,0x60,0x60,0x60,0x60,0x60,0x60,0x3C,0x00,0x00};
static unsigned char fnt_l[16] = {0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00};
static unsigned char fnt_o[16] = {0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00};
static unsigned char fnt_r[16] = {0x00,0x00,0x7C,0x66,0x66,0x66,0x7C,0x78,0x70,0x70,0x60,0x60,0x60,0x60,0x00,0x00};
static unsigned char fnt_f[16] = {0x3C,0x66,0x60,0x60,0x60,0xFC,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00};
static unsigned char fnt_m[16] = {0x00,0x00,0x66,0x7E,0x7E,0x7E,0x7E,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00};
static unsigned char fnt_P[16] = {0x7C,0x66,0x66,0x66,0x66,0x7C,0x78,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x00,0x00};
static unsigned char fnt_a[16] = {0x00,0x00,0x3C,0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00};
static unsigned char fnt_z[16] = {0x00,0x00,0x7E,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x00,0x00};
static unsigned char fnt_E[16] = {0x7E,0x60,0x60,0x60,0x60,0x7C,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x00,0x00};
static unsigned char fnt_c[16] = {0x00,0x00,0x3C,0x66,0x66,0x60,0x60,0x60,0x60,0x60,0x66,0x66,0x3C,0x00,0x00,0x00};
static unsigned char fnt_t[16] = {0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x7E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x00,0x00,0x00};
static unsigned char fnt_s[16] = {0x00,0x00,0x3C,0x66,0x60,0x60,0x3C,0x06,0x06,0x66,0x66,0x3C,0x00,0x00,0x00,0x00};
static unsigned char fnt_o2[16] = {0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00};
static unsigned char fnt_e2[16] = {0x00,0x00,0x3C,0x66,0x66,0x66,0x7E,0x60,0x60,0x60,0x60,0x60,0x60,0x3C,0x00,0x00};
static unsigned char fnt_ex[16] = {0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x18,0x18,0x18,0x00,0x00};
static unsigned char *getglyph(unsigned char c) {
if (c == 'H') return fnt_H;
if (c == 'e') return fnt_e;
if (c == 'l') return fnt_l;
if (c == 'o') return fnt_o;
if (c == 'r') return fnt_r;
if (c == 'f') return fnt_f;
if (c == 'm') return fnt_m;
if (c == 'P') return fnt_P;
if (c == 'a') return fnt_a;
if (c == 'z') return fnt_z;
if (c == 'E') return fnt_E;
if (c == 'c') return fnt_c;
if (c == 't') return fnt_t;
if (c == 's') return fnt_s;
if (c == '!') return fnt_ex;
return 0;
}
static void putch(unsigned int *fb, int pitch, int x, int y, unsigned char c, unsigned int fg, unsigned int bg) {
int row, col;
unsigned char *g = getglyph(c);
if (!g) return;
for (row = 0; row < 16; row++) {
unsigned char bits = g[row];
for (col = 0; col < 8; col++) {
unsigned int color = (bits & (0x80 >> col)) ? fg : bg;
if (x+col >= 0 && x+col < 480 && y+row >= 0 && y+row < 320)
fb[(y+row)*pitch + (x+col)] = color;
}
}
}
static void puts_fb(unsigned int *fb, int pitch, int x, int y, const char *s, unsigned int fg, unsigned int bg) {
int cx = x, cy = y, i;
for (i = 0; s[i]; i++) {
if (s[i] == '\n') { cx = x; cy += 18; continue; }
if (s[i] == ' ') { cx += 10; continue; }
putch(fb, pitch, cx, cy, s[i], fg, bg);
cx += 10;
}
}
int main(void) {
int fd = 3;
int W = 480, H = 320;
/* 创建窗口 */
struct create gc;
gc.width = W; gc.height = H;
gc.title = "PazeE Demo"; gc.text = "Hello";
gc.flags = 0;
int wid = paze_ioctl(fd, CREATE_WINDOW, &gc);
/* 分配帧缓冲区 */
unsigned int *fb = (unsigned int*)malloc((unsigned long)W * H * 4);
if (!fb) return 1;
memset(fb, 0xFF, (unsigned long)W * H * 4); /* ARGB32: 0xFFFFFFFF = 白色 */
/* 绘制文字(ARGB32: 0x000000FF = 黑色,0xFFFFFFFF = 白色)*/
puts_fb(fb, W, 20, 20, "Hello from PazeE!", COL_BLACK, COL_WHITE);
puts_fb(fb, W, 20, 50, "PazeE is awesome!", COL_BLACK, COL_WHITE);
puts_fb(fb, W, 20, 80, "Target: LeonOS 4 (los4)", COL_BLACK, COL_WHITE);
/* 提交帧缓冲区 */
struct present p;
p.window_id = (unsigned int)wid;
p.width = W;
p.height = H;
p.stride = W;
p.pixels = fb;
paze_ioctl(fd, PRESENT_WINDOW, &p);
/* 事件循环(仅在用户关闭窗口时退出)*/
struct wait_event wev;
while (1) {
wev.event.window_id = 0;
wev.event.type = 0;
wev.timeout_ms = 100;
int r = paze_ioctl(fd, WAIT_WINDOW_EVENT, &wev);
if (r > 0 && wev.event.type == 1) break;
}
return 0;
}
+2 -2
查看文件
@@ -1,7 +1,7 @@
/* Windows GUI 综合测试:多色文字、鼠标点击反馈、按键显示 */
struct gui_event { int type, key, mouse_x, mouse_y, button, window_id; };
int gui_init(void);
int gui_window_create(const char *title, int width, int height);
int gui_window_create(const char *title, const char *text, int width, int height);
int gui_window_text(int win, int x, int y, const char *text, unsigned int fg, unsigned int bg);
int gui_window_present(int win);
int gui_event_poll(struct gui_event *ev);
@@ -15,7 +15,7 @@ unsigned long strlen(const char *s);
int main(void) {
if (gui_init() < 0) return 1;
if (gui_window_create("PazeE Windows GUI Test", 600, 400) < 0) return 1;
if (gui_window_create("PazeE Windows GUI Test", "=== PazeE GUI Demo ===", 600, 400) < 0) return 1;
/* 标题行 — 亮白色 */
gui_window_text(0, 140, 30, "=== PazeE GUI Demo ===", 0xFFFFFF, 0x000000);