{"id":51384481,"url":"https://github.com/emproof-com/nyxstonetricoregcc","last_synced_at":"2026-07-03T19:01:08.417Z","repository":{"id":363317550,"uuid":"1255538910","full_name":"emproof-com/NyxstoneTricoreGCC","owner":"emproof-com","description":null,"archived":false,"fork":false,"pushed_at":"2026-06-15T23:40:56.000Z","size":3455,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-02T06:10:03.947Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/emproof-com.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-01T00:11:57.000Z","updated_at":"2026-06-15T23:40:56.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/emproof-com/NyxstoneTricoreGCC","commit_stats":null,"previous_names":["emproof-com/nyxstonetricoregcc"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/emproof-com/NyxstoneTricoreGCC","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emproof-com%2FNyxstoneTricoreGCC","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emproof-com%2FNyxstoneTricoreGCC/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emproof-com%2FNyxstoneTricoreGCC/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emproof-com%2FNyxstoneTricoreGCC/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/emproof-com","download_url":"https://codeload.github.com/emproof-com/NyxstoneTricoreGCC/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emproof-com%2FNyxstoneTricoreGCC/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35097760,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-03T02:00:05.635Z","response_time":110,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-03T19:01:06.956Z","updated_at":"2026-07-03T19:01:08.403Z","avatar_url":"https://github.com/emproof-com.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NyxstoneTricoreGCC\n\n[![ci](https://github.com/emproof-com/NyxstoneTricoreGCC/actions/workflows/ci.yml/badge.svg)](https://github.com/emproof-com/NyxstoneTricoreGCC/actions/workflows/ci.yml)\n[![crates.io: nyxstone-tricore-gcc](https://img.shields.io/crates/v/nyxstone-tricore-gcc.svg?label=nyxstone-tricore-gcc%20(GPL))](https://crates.io/crates/nyxstone-tricore-gcc)\n[![crates.io: nyxstone-tricore-gcc-ipc](https://img.shields.io/crates/v/nyxstone-tricore-gcc-ipc.svg?label=nyxstone-tricore-gcc-ipc%20(MIT))](https://crates.io/crates/nyxstone-tricore-gcc-ipc)\n[![PyPI](https://img.shields.io/pypi/v/nyxstone-tricore-gcc.svg)](https://pypi.org/project/nyxstone-tricore-gcc/)\n[![License: GPL-3.0-or-later](https://img.shields.io/badge/license-GPL--3.0--or--later-blue.svg)](LICENSE)\n\nIn-process TriCore assembler/disassembler.  C++17 library + Rust and Python\nbindings.  Built on the GNU assembler's TriCore encoder (`md_assemble`) and\nlibopcodes' `print_insn_tricore` decoder from a pinned\n[`emproof-com/tricore-binutils-gdb`](https://github.com/emproof-com/tricore-binutils-gdb)\nfork, fully compatible with upstream [EEESlab/tricore-binutils-gdb](https://github.com/EEESlab/tricore-binutils-gdb).\n\n```sh\n# Rust, pick your licensing mode (see \"License modes\" below):\ncargo add nyxstone-tricore-gcc        # GPL-3.0-or-later, in-process, ~2.8 M ops/s\ncargo add nyxstone-tricore-gcc-ipc    # MIT, IPC daemon, ~150 k ops/s\n\n# Python\npip install nyxstone-tricore-gcc\n```\n\nSupported prebuilts: `x86_64-linux-gnu`, `aarch64-linux-gnu`.  Other hosts\nbuild binutils-tricore from source automatically (see *Binutils provisioning*\nbelow).\n\nThe public API mirrors that of the sibling project\n[Nyxstone](https://github.com/emproof-com/nyxstone), a different\nimplementation built on LLVM-MC that covers the architectures LLVM supports.\nNyxstoneTricoreGCC is **not** a fork or downstream of Nyxstone; it's an\nindependent codebase using GNU binutils to cover TriCore (which LLVM-MC\ndoesn't).  Both projects expose six assemble/disassemble methods with the\nsame argument order (`source` / `bytes`, `address`, then either `labels` or\n`count`):\n\n| method | purpose |\n|---|---|\n| `assemble` | bytes only, labels resolved inline |\n| `assemble_to_instructions` | per-insn records, labels resolved inline |\n| `assemble_with_relocs` | bytes + relocations (gcc/gas `-r` equivalent) |\n| `assemble_to_instructions_with_relocs` | per-insn records + relocations |\n| `disassemble` | bytes → text |\n| `disassemble_to_instructions` | bytes → per-insn records |\n\n- **No fork/exec in the hot path.** All work happens in the calling process\n  (or in a long-lived per-instance daemon for the MIT-licensed Rust binding).\n- **`.text`-only.** Any directive that would switch the active section to\n  anything other than `.text` makes `assemble()` fail.\n- **Stock binutils.** Uses an unmodified `emproof-com/tricore-binutils-gdb`\n  build, no patches to gas, libbfd, or libopcodes.\n- **Byte-equivalent to `tricore-elf-as`.** PC-relative branches with forward\n  references go through a mini relax + `md_apply_fix` pass; `.align`/`.org`\n  padding is sized *after* relaxation, exactly like gas.\n- **Loud failures, real diagnostics.** gas's stderr is captured and embedded\n  in the returned error (`Error: Opcode/operand mismatch: mov %d0, 0x123456`),\n  never printed to the host process.  In the plain `assemble` /\n  `assemble_to_instructions` paths, references to labels that are neither\n  defined in the source nor supplied via `LabelDefinition` are an error, not\n  a silent zero displacement; same for `.org` moving backwards, unknown\n  directives, and out-of-range branch displacements.  The `*_with_relocs`\n  variants are the link-later path: undefined references are *not* an error\n  there -- each one comes back as a relocation record (zero placeholder bytes\n  + `R_TRICORE_*` entry, gas `-r` style) for the linker to resolve.\n\n## License modes\n\nThe project ships **two Rust crates with byte-identical public APIs** so you\ncan pick the licensing mode that fits your situation by changing one line in\n`Cargo.toml`:\n\n| crate | license | mode | per-op | typical use |\n|---|---|---|---|---|\n| **`nyxstone-tricore-gcc`**     | GPL-3.0-or-later | in-process (links gas) | ~360 ns | open-source / GPL-compatible projects |\n| **`nyxstone-tricore-gcc-ipc`** | MIT | IPC to GPL daemon       | ~6 µs   | closed-source / commercially permissive |\n\nThe MIT crate spawns a separate daemon binary (`nyxstone-tcd`, GPL-3.0+) and\ntalks to it over a `socketpair(2)` UNIX socket, one daemon per\n`NyxstoneTricoreGCC` instance, lazy-spawn, exiting when the instance is\ndropped or the parent dies (socket EOF; deliberately not `PR_SET_PDEATHSIG`,\nwhich is thread-scoped).  Strict FIFO, 30 s request timeouts, automatic\none-shot daemon respawn if it crashes mid-session.  See\n[`bindings/rust-ipc/README.md`](bindings/rust-ipc/README.md) for the binary\ndependency and three daemon-install methods (`cargo install`, `cargo\nbinstall`, programmatic bootstrap).\n\nThe C++ and Python bindings only ship in GPL form today, they statically\nlink gas in-process for full speed.  If you need permissive licensing for\nC++ or Python too, use the Rust MIT crate via a thin FFI or open an issue.\n\n## Quick start\n\n`make` Just Works™, it auto-extracts the committed binutils prebuilts\n(`third_party/binutils-tricore-prebuilt/`, ~3 MB across x86_64+aarch64,\nnopic+pic) on first run, no network access needed:\n\n```sh\n# 1. Build the C++ library + tests + examples (~5 s on first run).\nmake                    # or:  cmake -S . -B build \u0026\u0026 cmake --build build -j\n\n# 2. Run the test suite (162 + extra API tests).\nmake test               # or:  ctest --test-dir build --output-on-failure\n\n# 3. Try an example.\n./smoke                 # round-trip a handful of TriCore insns\n./bench 2.0             # throughput benchmark, 2-second window\n```\n\nFor the Rust binding (GPL in-process mode):\n\n```sh\ncd bindings/rust\nNYX_LIB_DIR=.. cargo build --release\nNYX_LIB_DIR=.. cargo test --release\n```\n\nFor the Rust binding (MIT IPC mode):\n\n```sh\ncd bindings/rust \u0026\u0026 cargo build --release --bin nyxstone-tcd   # build the daemon\ncd ../rust-ipc\nNYXSTONE_TCD_PATH=../rust/target/release/nyxstone-tcd \\\n    cargo test --release\n```\n\nFor the Python binding (requires `pip install cffi setuptools`):\n\n```sh\n# Python's CFFI extension needs -fPIC binutils objects; use the PIC variant.\nNYX_BINUTILS_PIC=1 make\n(cd bindings/python \u0026\u0026 python3 setup.py build_ext --inplace)\n(cd bindings/python \u0026\u0026 PYTHONPATH=. python3 examples/smoke.py)\n```\n\n### Binutils provisioning details\n\n| source | trigger | time |\n|---|---|---|\n| **prebuilt** (default, x86_64 / aarch64 Linux) | `make` extracts `third_party/binutils-tricore-prebuilt/$(uname -m)-linux-gnu/{nopic,pic}/lib.tar.xz` automatically | **~1 s** |\n| **from source** (other arches, or `make fetch_binutils`) | `scripts/fetch_binutils.sh`, clone emproof-com fork, configure, build, stage | **~75 s** |\n\nOverride the binutils tree wholesale with `make NYX_BINUTILS=/path/to/tree`.\n\n## API\n\n### C++ (`#include \u003cnyxstone/nyxstone.h\u003e`)\n\n```cpp\nnamespace nyxstone {\n\nusing Address = uint64_t;\n\nstruct RelocationSymbol { std::string name; Address address; };\nstruct RelocationInfo {\n    Address offset;\n    std::optional\u003cint64_t\u003e addend;\n    RelocationSymbol symbol;\n    uint32_t relocation_type;     // ELF R_TRICORE_*\n};\n\nclass NyxstoneTricoreGCC {\npublic:\n    struct LabelDefinition { std::string name; Address address; };\n    struct Instruction     { Address address; std::string assembly; std::vector\u003cuint8_t\u003e bytes; };\n\n    struct AssembleWithRelocsResult {\n        std::vector\u003cuint8_t\u003e bytes;\n        std::vector\u003cRelocationInfo\u003e relocations;\n    };\n    struct AssembleInstructionsWithRelocsResult {\n        std::vector\u003cInstruction\u003e instructions;\n        std::vector\u003cRelocationInfo\u003e relocations;\n    };\n\n    static tl::expected\u003cstd::unique_ptr\u003cNyxstoneTricoreGCC\u003e, std::string\u003e create();\n\n    tl::expected\u003cstd::vector\u003cuint8_t\u003e, std::string\u003e assemble(\n        const std::string\u0026 assembly, Address address,\n        const std::vector\u003cLabelDefinition\u003e\u0026 labels) const;\n\n    tl::expected\u003cstd::vector\u003cInstruction\u003e, std::string\u003e assemble_to_instructions(\n        const std::string\u0026 assembly, Address address,\n        const std::vector\u003cLabelDefinition\u003e\u0026 labels) const;\n\n    tl::expected\u003cAssembleWithRelocsResult, std::string\u003e assemble_with_relocs(\n        const std::string\u0026 assembly, Address address,\n        const std::vector\u003cLabelDefinition\u003e\u0026 labels) const;\n\n    tl::expected\u003cAssembleInstructionsWithRelocsResult, std::string\u003e\n    assemble_to_instructions_with_relocs(\n        const std::string\u0026 assembly, Address address,\n        const std::vector\u003cLabelDefinition\u003e\u0026 labels) const;\n\n    tl::expected\u003cstd::string, std::string\u003e disassemble(\n        const std::vector\u003cuint8_t\u003e\u0026 bytes, Address address, size_t count) const;\n\n    tl::expected\u003cstd::vector\u003cInstruction\u003e, std::string\u003e disassemble_to_instructions(\n        const std::vector\u003cuint8_t\u003e\u0026 bytes, Address address, size_t count) const;\n};\n\n}\n```\n\n`tl::expected` is the Sy Brand single-header\n([`include/nyxstone/expected.hpp`](include/nyxstone/expected.hpp)), no\nexternal dependency.\n\n### C ABI (`#include \u003cnyxstone_c.h\u003e`)\n\n```c\ntypedef struct nyxstone_handle nyxstone_handle_t;\ntypedef struct { const char* name;  uint64_t address; } nyxstone_label_def_t;\ntypedef struct { uint64_t address;  char* assembly;\n                 uint8_t* bytes;    size_t bytes_len; } nyxstone_instruction_t;\n\nnyxstone_handle_t* nyxstone_create(char** out_err);\nvoid                        nyxstone_destroy(nyxstone_handle_t*);\n\nint nyxstone_assemble(nyxstone_handle_t*, const char* src, size_t src_len,\n                 uint64_t address,\n                 const nyxstone_label_def_t* labels, size_t labels_len,\n                 uint8_t** out_bytes, size_t* out_len,\n                 char** out_err);\nint nyxstone_assemble_to_instructions(/* same args, instr array out */);\nint nyxstone_disassemble(nyxstone_handle_t*, const uint8_t* bytes, size_t bytes_len,\n                    uint64_t address, size_t count,\n                    char** out_text, char** out_err);\nint nyxstone_disassemble_to_instructions(/* same args, instr array out */);\n\nvoid nyxstone_free_bytes(uint8_t*);\nvoid nyxstone_free_string(char*);\nvoid nyxstone_free_instructions(nyxstone_instruction_t*, size_t);\n```\n\n### Rust, same code, two crates\n\nBoth crates expose `NyxstoneTricoreGCC` with identical method signatures.\nSwitching is a one-line `Cargo.toml` change:\n\n```rust\n// Same user code for both crates, only the use-path differs.\nuse nyxstone_tricore_gcc::{LabelDefinition, NyxstoneTricoreGCC};         // GPL crate\n// or:\nuse nyxstone_tricore_gcc_ipc::{LabelDefinition, NyxstoneTricoreGCC};     // MIT crate\n\nlet nx = NyxstoneTricoreGCC::new()?;\nlet bytes  = nx.assemble(\"nop; ret\", 0, \u0026[])?;\nlet insns  = nx.disassemble_to_instructions(\u0026bytes, 0x1000, 0)?;\nlet bytes2 = nx.assemble(\"nop; nop; j ext\", 0x1000,\n                         \u0026[LabelDefinition::new(\"ext\", 0x2000)])?;\n\n// gcc/gas -r equivalent, external labels stay as relocs in the byte stream.\nlet (rel_bytes, relocs) = nx.assemble_with_relocs(\n    \"nop\\n j ext\\n\", 0x1000,\n    \u0026[LabelDefinition::new(\"ext\", 0x2000)])?;\n// relocs[0] = { offset: 0x1002, symbol: { name: \"ext\", address: 0x2000 },\n//               relocation_type: 3 /* R_TRICORE_24REL */, addend: Some(0) }\n// offset is the absolute address of the reloc site: base 0x1000 + 2-byte nop.\n```\n\nThe MIT crate additionally exposes three bootstrap helpers for daemon\ninstallation (`install_daemon_if_missing`, `install_daemon`, `daemon_path`)\nso you can avoid documenting a separate `cargo install` step in your own\nREADME:\n\n```rust\nfn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    // Optional zero-config bootstrap (prefers `cargo binstall` if available).\n    nyxstone_tricore_gcc_ipc::install_daemon_if_missing()?;\n    let nx = nyxstone_tricore_gcc_ipc::NyxstoneTricoreGCC::new()?;\n    // ... use nx ...\n    Ok(())\n}\n```\n\nSee [`bindings/rust-ipc/README.md`](bindings/rust-ipc/README.md) for full\ndetails on the IPC architecture, daemon lifecycle, and license boundary.\n\n### Python\n\n```python\nfrom nyxstone_tricore_gcc import LabelDefinition, NyxstoneTricoreGCC\nnx = NyxstoneTricoreGCC()\nbytes_ = nx.assemble(\"nop; ret\", address=0)\nfor ins in nx.disassemble_to_instructions(bytes_, address=0x1000):\n    print(f\"0x{ins.address:08x}  {ins.assembly}\")\next = nx.assemble(\"nop\\n j ext\\n\",\n                  address=0x1000,\n                  labels=[LabelDefinition(\"ext\", 0x2000)])\n\n# gcc/gas -r equivalent: bytes + relocations.\nrel_bytes, relocs = nx.assemble_with_relocs(\n    \"nop\\n j ext\\n\",\n    address=0x1000,\n    labels=[LabelDefinition(\"ext\", 0x2000)])\n# relocs[0] == RelocationInfo(offset=0x1002, addend=0,   # absolute: base + nop\n#                             symbol=RelocationSymbol(name=\"ext\", address=0x2000),\n#                             relocation_type=3)  # R_TRICORE_24REL\n```\n\n## Benchmarks\n\nHot-cache throughput measured by `examples/bench.cpp` (single-threaded,\n20-core x86_64 i7-1370P, gcc 14.2.0, `-O3`).  Numbers are ops/second on the\n`assemble` / `disassemble_to_instructions` path, fully resetting gas's\nstate and re-running the encoder on each call.\n\n| backend | per-op (1-insn) | ops/s (1-insn) | insns/s (10-insn batch) |\n|---|---|---|---|\n| C++ in-process               | ~360 ns | ~2.78 M | ~4.84 M |\n| Rust GPL (in-process)        | ~410 ns | ~2.45 M | ~4.70 M |\n| **Rust MIT (IPC daemon)**    | **~6 µs** | **~167 k**  | **~1.14 M** |\n| process-spawn (`tricore-elf-as` baseline) | ~2.6 ms | ~385  | – |\n\nThe MIT mode pays ~15× over the GPL in-process path at the 1-insn level for\nthe license-clean process boundary.  Batching client-side (e.g., 10\ninstructions per request) closes most of the gap.\n\nReproduce locally:\n\n```sh\nmake \u0026\u0026 ./bench 2.0                                           # C++\ncd bindings/rust     \u0026\u0026 cargo run --release --example bench   # GPL crate\ncd bindings/rust-ipc \u0026\u0026 NYXSTONE_TCD_PATH=../rust/target/release/nyxstone-tcd \\\n                        cargo run --release --example bench   # MIT crate\n```\n\n## Layout\n\n```\nNyxstoneTricoreGCC/\n├── include/nyxstone/\n│   ├── nyxstone.h                 Public C++ API\n│   └── expected.hpp               Sy Brand's tl::expected (vendored, header-only)\n├── c_api/nyxstone_c.h             Public C ABI\n├── src/\n│   ├── nyxstone.cpp               C++ implementation\n│   ├── nyxstone_glue.c            The only TU that touches gas internals\n│   └── nyxstone_c.cpp             C ABI wrapper\n├── tests/tests.cpp                162-test matrix + stress + round-trip + API checks\n├── examples/{smoke,bench}.cpp     Demo and throughput benchmark\n├── bindings/\n│   ├── rust/                      nyxstone-tricore-gcc (GPL) crate + nyxstone-tcd daemon\n│   │   └── src/bin/nyxstone-tcd.rs  GPL daemon binary served via cargo install\n│   ├── rust-ipc/                  nyxstone-tricore-gcc-ipc (MIT) IPC client crate\n│   └── python/                    setuptools + CFFI extension\n├── scripts/\n│   ├── fetch_binutils.sh          Clone + build binutils from source\n│   ├── build_prebuilts.sh         Refresh all 4 prebuilt tarball variants\n│   └── extract_prebuilt.sh        Extract host-matching prebuilt into third_party/\n├── third_party/\n│   ├── binutils-tricore-prebuilt/ Committed prebuilts (~3 MB compressed)\n│   └── binutils-tricore/          Extracted-on-demand working tree (gitignored)\n├── docs/architecture.md           How the library is plumbed together\n├── Makefile                       Simple build\n└── CMakeLists.txt                 Production build with install\n```\n\n## Tests\n\n`tests/tests.cpp` ships a 162-test matrix split into twelve groups:\n\n- **insn** (47): every TriCore format we exercise (SR/SRR/SLR/SSR/SC/SRC/RC/\n  RR/RLC/B), various register kinds, immediate widths, signedness.\n- **label** (12): forward + backward branches, multi-label lines\n  (`a: b: nop`), `.L0`/`$x`/`_x` naming variants, label-only sources.\n- **relax** (2): local branches shrink to their 2-byte short form in both\n  directions.\n- **data** (36): every data directive Nyxstone supports, `.byte` /\n  `.half` / `.hword` / `.short` / `.2byte` / `.word` / `.int` / `.long` /\n  `.4byte` / `.quad` / `.8byte` / `.ascii` / `.asciz` / `.string` /\n  `.skip` / `.space` / `.zero` / `.org` / `.align` / `.balign`.\n- **mixed** (4): instructions + labels + data interleaved.\n- **edge** (9): empty / comments-only / whitespace / `;` separators.\n- **forbid** (7+3): `.text`-only restriction, `.data` / `.bss` /\n  `.section .foo` / `.pushsection` must all reject; `.text` / `.section\n  .text*` must accept.\n- **quote** (6): `#` / `;` / `//` / `/* */` inside string literals survive\n  the tokenizer (`.asciz \"a#b\"` keeps its hash).\n- **comment** (6): `/* */` block comments, including mid-line, whole-line,\n  multi-line, and unterminated, are stripped like gas's input scrubber.\n- **dirsem** (13): `.skip`/`.space`/`.align` fill operands, `.align`\n  max-skip, `.p2align`, `.equ`/`.set` constants and label expressions,\n  numeric local labels (`1:` / `1b` / `1f`, including instance reuse).\n- **alignrelax** (4): `.align`/`.org` padding is sized *after* branch\n  relaxation -- a shrinking branch before the directive must not shift\n  the alignment.\n- **error** (13): undefined labels, unknown directives/mnemonics,\n  duplicate labels, `.org` backwards, non-power-of-2 `.balign`,\n  out-of-range immediates -- all must reject instead of emitting silently\n  wrong bytes.\n\nAfter the core matrix, post-matrix checks (194 assertions) cover:\n\n- 100× stress per test catches state-reset drift across consecutive\n  `assemble()` calls.\n- Every BYTES test of ≥2 bytes is round-tripped through\n  `disassemble_to_instructions()` (128 cases).\n- `LabelDefinition` external symbols (exact displacement bytes + address\n  invariance), the `address` parameter propagating to `Instruction.address`,\n  the `count` parameter, relocation records, and branch displacement\n  semantics (decoded target == label address).\n- **Resolution-path relocation encodings**: every TriCore relocation the\n  library resolves in place is a faithful transcription of gas's\n  `md_apply_fix`, including the *non-linear* forms a naive mask heuristic\n  silently mis-encoded -- the split B-format 24-bit displacement (24REL/\n  24ABS), the carry-adjusted high half (HI/HIADJ, `movh hi:`), the permuted\n  16-bit offset (16OFF/LO2), and 18-bit absolute addressing (18ABS,\n  `lea`/`ld.w`/`st.w`).\n- **Relocation offsets** are absolute (base + section position) and stay\n  correct through relaxation, `.align`/`.org` padding, and interleaved data;\n  the `symbol.address` hint resolves through every binding.\n- **ISA level**: the assembler accepts the v1.6/1.6.2 instruction set the\n  disassembler decodes (`fret`, `fcall`, `cmpswap.w`, ...) -- gas's default\n  v1.2 silently rejected them.\n- **Disassembly is re-assemblable**: the objdump-style ` \u003c0x..\u003e` symbolic-\n  address annotation (after a `movh.a`+`lea`/`ld`/`st` sequence) is stripped,\n  and load/store/lea references to labels resolve to the right address.\n- The **data fast-path** (`emit_int_list`) is byte-checked against gas's\n  `cons` for every value (overflow, sign, all bases).\n- An **instruction idempotence corpus** (one per major format) pins both\n  the disassembler (bytes → text) and assembler/disassembler agreement\n  (text → bytes → text), the property the round-trip fuzzer verified across\n  the full 16-bit space and a 2.1M-case 32-bit sample.\n- Error-message quality (gas diagnostics + offending symbol names appear in\n  the returned error; nothing leaks to the host stderr) and 32-bit masking\n  of printed branch targets.\n\nA separate `roundtrip_all` test (also run by `make test`) is exhaustive over\nthe **whole v1.6.2 instruction set**: it drives all 398 instruction/format\nentries from the pinned binutils opcode table (extracted by\n[`scripts/gen_v162_corpus.py`](scripts/gen_v162_corpus.py) into\n[`tests/tricore_v162_insns.inc`](tests/tricore_v162_insns.inc)), synthesizing\noperands from each instruction's arg-spec across two parameter variants (low\nregisters + mid immediates, and high registers + extreme immediates).  Every\ninstruction must assemble in both variants; every non-branch form must\nround-trip idempotently (`disassemble → assemble → disassemble` stable); and\nevery branch/absolute/symbol operand must resolve both inline (label address\nrecovered in the disassembly) and as a relocation (`assemble_with_relocs`\nyields the right symbol, absolute offset, and address). PC-relative branches\nare validated only via the reference path, since the disassembler prints an\nabsolute target that gas re-reads as a displacement (upstream convention).\n\n```\n=== TriCore v1.6.2 exhaustive round-trip ===\ninstruction/format entries:  398\nassembled (variant A):       398  (100.0%)\nassembled (variant B):       398  (high regs / extreme immediates)\nround-trip idempotent:       375 / 375 checked (non-branch)\nreference/reloc resolved:    25 / 25\nOK\n```\n\nThe Rust crates run the same unit tests (verbatim sources, only the\n`use` line differs between `nyxstone-tricore-gcc` and `nyxstone-tricore-gcc-ipc`)\nplus one doctest each, and produce byte-identical output across both\nbackends; the IPC crate adds daemon-resilience tests (kill-then-respawn,\nprotocol frame caps).\n\n```\n$ ./run_tests\n... (162 tests in 12 groups) ...\n--- 100x stress (each non-MUST_FAIL test 100 iterations) ---\n  PASS: no drift across 142 non-fail tests * 100 iterations\n--- disassembly round-trip ---\n  128 round-trip pass, 0 fail\n--- resolution-path reloc encodings ---\n  12 resolution-reloc pass, 0 fail\n--- relocation offsets ---\n  7 reloc-offset pass, 0 fail\n--- data fast-path vs gas cons ---\n  88 data-fastpath pass, 0 fail\n--- idempotence corpus ---\n  33 idempotence-corpus pass, 0 fail\n--- v1.6 instruction set / annotation strip / load-store label resolution ---\n  5 v1.6-isa, 4 annotation-strip, 9 load-store-label pass, 0 fail\n  ... (external-label, relocs, branch, error-message, masking checks) ...\nSummary: 162 passed, 0 failed, 0 drifts (of 162 tests);\n         128 disasm round-trips passed, 0 failed;\n         194 additional API checks passed, 0 failed\n```\n\n## Threading\n\nSingle-threaded only at the gas layer.  All gas globals are process-wide;\nconcurrent calls from multiple threads would corrupt state.\n\n- The C++ API does not lock, callers must serialize.\n- The Rust GPL binding holds a global `Mutex\u003c()\u003e` per call so calls from\n  multiple threads are safe (they're just serialized).  `NyxstoneTricoreGCC`\n  is both `Send` and `Sync`.\n- The Rust MIT binding holds a per-instance `Mutex` around the UDS socket,\n  same FIFO contract, scoped per-handle since each MIT-mode instance has\n  its own daemon process.\n- The Python binding holds a `threading.Lock()` per call.\n\n## License\n\n**GPL-3.0-or-later** for the C++/C/Python parts and the `nyxstone-tricore-gcc`\nRust crate.  These statically link GNU assembler (`gas`) object files from\nbinutils, which are GPL-3.0-or-later; that propagates to the combined\nlibrary and to any binary distribution.  libbfd and libopcodes\n(LGPL-3.0-or-later) are subsumed by the GPL term.\n\n**MIT** for the `nyxstone-tricore-gcc-ipc` Rust crate, it ships\nzero GPL bytes and only talks to a separate `nyxstone-tcd` daemon binary\n(GPL-3.0+) over an IPC socket.  Shipping the daemon alongside a commercial\nproduct follows the same well-trodden pattern as bundling `gcc.exe` next to\na closed-source IDE.\n\nSee [LICENSE](LICENSE), [LICENSE-MIT](LICENSE-MIT), and\n[`bindings/rust-ipc/README.md`](bindings/rust-ipc/README.md) for the full\nstory on the license-mode split.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femproof-com%2Fnyxstonetricoregcc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Femproof-com%2Fnyxstonetricoregcc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femproof-com%2Fnyxstonetricoregcc/lists"}