Menu

#3999 Out-of-range branch generated by SDCC

closed-fixed
mos6502 (4)
MOS6502
5
2026-06-08
2026-06-02
No

When compiling with the latest nightly build for mos6502, the compiler sometimes generates an .asm file which has an out-of-range branch address.
In these cases it would be expected to add an unconditional jmp instruction, and a branch with the opposite condition.

Tested with 4.6.0 #16555 (MINGW64)
(sdcc-snapshot-x86_64-w64-mingw32-20260602-16555)

Building with:

sdcc -mmos6502 -c out_of_range_branch_codegen.c

Error

out_of_range_branch_codegen.asm:147: Error: <a> machine specific addressing or addressing mode error

Minimal example to reproduce:

//
// Generates a codegen error for 6502: A branch instruction trying to jump beyond a signed 8-bit relative PC value
//
#include <stdint.h>

uint16_t X, Y;
int16_t Z;

uint8_t f(uint16_t x)
{
    return x + 42;
}

void main(void)
{
    uint16_t x = X >> 4;
    if(Z > 0)
    {
        if(f(x) || f(x+1) || f(x+2) || f(x+3) || f(x+4) || f(x+5) || f(x+6))
        {
            return;
        }
    }
}
1 Attachments

Discussion

  • Philipp Klaus Krause

    I can reproduce the issue on my Debian GNU/Linux testing system using sdcc built from current trunk.

     
  • bbbbbr

    bbbbbr - 2026-06-04

    Just subscribing to this ticket

     
  • Gabriele Gorla

    Gabriele Gorla - 2026-06-07

    bug is confirmed. I have a fix. I'll send a mail to the devel list to confirm it's ok to check-in before 4.6.0 release.

     
  • Gabriele Gorla

    Gabriele Gorla - 2026-06-07
    • assigned_to: Gabriele Gorla
     
  • Gabriele Gorla

    Gabriele Gorla - 2026-06-07
    Index: src/mos6502/gen.c
    ===================================================================
    --- src/mos6502/gen.c   (revision 16596)
    +++ src/mos6502/gen.c   (working copy)
    @@ -5361,6 +5361,7 @@
       symbol *true_lbl = NULL;
       symbol *false_lbl = NULL;
       bool needloada = false;
    
    +  symbol *skiplbl = NULL;
    
       opcode = ic->op;
    
    @@ -5415,6 +5416,8 @@
    
       if (ifx)
         {
    
    +      skiplbl = m6502_safeNewiTempLabel (NULL);
    +
           if (IC_TRUE (ifx))
             {
               ifx_jmp_lbl = IC_TRUE (ifx);
    @@ -5452,11 +5455,11 @@
    
           if(ifx)
             {
    
    -          symbol *skiplbl = m6502_safeNewiTempLabel (NULL);
    +          symbol *skiplbl1 = m6502_safeNewiTempLabel (NULL);
    
    
    -          m6502_emitBranch ("bpl", skiplbl);
    +          m6502_emitBranch ("bpl", skiplbl1);
                                      m6502_emitBranch ("jmp", ifx_jmp_lbl);
    -          m6502_safeEmitLabel (skiplbl);
    +          m6502_safeEmitLabel (skiplbl1);
             }
           else
             {
    @@ -5467,7 +5470,7 @@
           if(size==2)
             {
               if(ifx)
    -            m6502_emitBranch ("bne", ifx_jmp_lbl);
    +            m6502_emitBranch ("bne", skiplbl);
               else
                 m6502_emitBranch ("bne", true_lbl);
    
    @@ -5607,8 +5610,6 @@
    
       if (ifx)
         {
    
    -      symbol *skiplbl = m6502_safeNewiTempLabel (NULL);
    -
           if(needloada)
             {
          if (!strcmp(br_inst, "bcc") || !strcmp(br_inst, "bcs"))
    

    quick description:
    There was a logic bug in the original code. ifx_jmp_lbl was used instead of skiplbl
    move skiplbl definition at the beginning of the function.
    rename skiplbl to skiplbl1 for the first byte.
    use skiplbl instead of ifx_jmp_lbl

     
  • Gabriele Gorla

    Gabriele Gorla - 2026-06-08

    fixed in [r16601]

     

    Related

    Commit: [r16601]

  • Gabriele Gorla

    Gabriele Gorla - 2026-06-08
    • status: open --> closed-fixed
     

Log in to post a comment.

Auth0 Logo