asm_branch() had two identical 15-case switch blocks (30 lines total)
that duplicated condition code mapping. This also duplicated the logic
in the existing parse_condition() helper.
Added get_branch_condition() helper that:
1. Maps branch tokens (TOK_ASM_beq) to condition tokens (TOK_ASM_eq)
2. Calls the existing parse_condition() helper
3. Returns the condition code (0-13) or -1 for non-conditional branches
This reduces code duplication from 30 lines to a single 29-line helper
function, and ensures all condition mapping logic is in one place.
Multiple instruction handlers were extracting op->reg without checking
that the operand was actually a register. When parse_operand() failed
to recognize a token, it set op->reg = -1, which when masked with 0x1F
became 31 (xzr/sp), silently encoding wrong instructions.
Now each handler validates operand types before extraction:
- asm_shift: validates op1 and op2 are registers
- asm_data_proc: validates op1, op2, and op3 are registers
- asm_ldst: validates op1 is register, op2 is address
- asm_ldst_pair: validates op1 and op2 are registers, op3 is address
This implements fail-fast behavior to catch typos and invalid operands
immediately rather than producing silently incorrect code.
Previously, parse_operand() would silently accept any unrecognized token
and pass it to asm_expr() as an immediate, causing typos like:
add x0, x1, xyz ; 'xyz' is not a valid register
to be silently assembled as a symbol reference instead of erroring.
Now, if a token is not a register, condition code, or valid immediate
prefix (#, :, @, $), an error is emitted for identifier tokens.
This implements fail-fast behavior for invalid operands, making it easier
to catch typos and mistakes in assembly code.
The fallback CONTEXT definition at lines 2073-2124 was unreachable dead code.
The guard '#if defined(__aarch64__) && !defined(_ARM64_CONTEXT_DECLARED)'
could never be true because:
1. Line 50-51: __aarch64__ automatically defines _ARM64_
2. Line 1426: #if defined(_ARM64_) || defined(__aarch64__) always enters
3. Line 1473: _ARM64_CONTEXT_DECLARED is always defined inside that block
4. Line 2073: The fallback guard is therefore always false
This 52-line duplicate was a maintenance hazard that could silently diverge
from the official ARM64_NT_CONTEXT definition. Remove it entirely.
The fallback CONTEXT struct incorrectly defined Bvr (Breakpoint Value
Registers) and Wvr (Watchpoint Value Registers) as DWORD (32-bit) instead
of DWORD64 (64-bit).
On ARM64:
- BCR/WCR (Control Registers) are 32-bit ✓
- BVR/WVR (Value Registers) are 64-bit ✓
This mismatch caused struct size and layout errors, potentially corrupting
debug register state when used with Windows debugging APIs.
These macros were defined twice (lines ~273 and ~317) with identical
values and #ifndef guards. The duplicates appear to be a copy-paste
oversight from adding ARM64 support.
Remove the redundant second set of defines. The first set (lines 273-284)
already provides the fallback definitions needed when Windows headers
are unavailable.
The fallback CONTEXT struct for ARM64 had multiple structural issues:
- ContextFlags was DWORD64 (8 bytes) instead of ULONG (4 bytes)
- Missing Cpsr field entirely
- Missing DECLSPEC_ALIGN(16) attribute
- X registers as simple array X[29] instead of union with named struct X[31]
These mismatches caused incorrect struct size and field offsets, leading to
register corruption when used with Windows APIs like GetThreadContext or
RtlRestoreContext.
The fallback struct now matches the official ARM64_NT_CONTEXT layout exactly,
ensuring binary compatibility with Windows ARM64 system calls.
The asm_data_proc function was OR-ing register widths together, which
allowed invalid ARM64 instructions like 'add x0, w1, w2' (mixed widths).
ARM64 requires all registers in data processing instructions to have
the same width (all X or all W).
Fix by validating that all three operand registers have matching widths
and emitting an error if they don't match.
pe_get_process_msvcrt_handle() used LoadLibraryA which increments the
module reference count, but never called FreeLibrary to release it.
Use GetModuleHandleA instead, which returns a handle to the already-
loaded msvcrt.dll module without incrementing the reference count.
This is the correct API for accessing system DLLs that are already
mapped into the process address space.
The fallback CONTEXT struct for ARM64 (used when __aarch64__ is defined
but _ARM64_CONTEXT_DECLARED is not set) incorrectly defined V[32] as
DWORD64 (64-bit) instead of ARM64_NT_NEON128 (128-bit).
This caused register corruption when RtlRestoreContext restores NEON/VFP
registers, as the struct size was 256 bytes instead of the correct
512 bytes.
Fixes potential corruption on toolchains that define __aarch64__ but not
_ARM64_ (e.g., clang on macOS or certain cross-compilation scenarios).
Improve the warning about an integer constant overflow with the used
overflown value and the potentially aimed value.
This helps spotting the 0 to much in 0x80000000000000000.
Track R_RISCV_PCREL_HI20/GOT_HI20 relocations by address and resolve LO12 relocations against the referenced HI, instead of only using the last seen HI.
Also reset/free the per-link relocation map in TCCState.
Moving the u128_t struct may invoke calls to memcpy/memmove when
compiled with tinycc, which would depend on libc.
For example, some configure scripts get confused if they fail to build
test programs involving long doubles. I'm not sure if this is the root
cause, though.
This reverts commit 41fa74fc84.
Reasons for the revert:
1. The commit message is lacking and the use case is not obvious.
At the very least a concrete example of use case should be given
(likely cross-building tcc on platform X for running on platform Y),
followed by an issue description in such use case, and fix descr.
(e.g. "On platform X, when running ./configure ... && make ..., the
build fails because whatever. this commit does Y and fixes it").
2. assign_opt is used incorrectly: 1st arg must be --OPTNAME=VALUE
but it's not. The only thing it does is unconditional host_cc=gcc
if --cross-prefix=... is used - no need for "assign_opt" at all.
3. cross-building tcc currently has several triggers: build/target
cpu differ, or build/target OS differ, or --cross-prefix=... is
used, but that commit only covers the --cross-prefix=... case.
It's possible that it's intentional to only cover one case, but
if so then it's not explained why.
4. The var name host_cc is likely incorrect and probably meant to be
"native_cc", judging by the assigned value "gcc".
5. "gcc" is used unconditionally in such case, without any way to use
a different native compiler (assuming that's indeed the goal).
A better approach is likely supporting --native-cc=... option which
defaults to $cc (which already defaults to "gcc") _before_
$cross_prefix is added in-front.