itszor/gcc-6502

Variables with internal linkage are placed in the CODE segment

LHLaurini opened this issue · 3 comments

First of all, fantastic work with this port. Now to the issue.

When I compile this:

#include <stdint.h>

volatile uint8_t x = 0;

int main()
{
    x = 1;
}

with 6502-gcc -O2 -S test.c -o-, the variable is in the BSS segment (correct):

        ; ...
        .segment "CODE"
        .export main
main:
; frame size 0, pretend size 0, outgoing size 0
        lda #$01
        sta x$
        lda #$00
        sta _r0
        sta _r1
        rts
        .export x$
        .segment "BSS"
x$:
.res 1,$00

If I compile it with 6502-gcc -O2 -S test.c -o- -fwhole-program, however, it's left in the CODE segment:

        ; ...
        .segment "CODE"
        .export main
main:
; frame size 0, pretend size 0, outgoing size 0
        lda #$01
        sta x$
        lda #$00
        sta _r0
        sta _r1
        rts
x$:
        .res 1

When I compile this:

#include <stdint.h>

static volatile uint8_t x = 0;

int main()
{
    x = 1;
}

with 6502-gcc -O2 -S test.c -o-, the same happens:

        ; ...
        .segment "CODE"
        .export main
main:
; frame size 0, pretend size 0, outgoing size 0
        lda #$01
        sta x$
        lda #$00
        sta _r0
        sta _r1
        rts
x$:
        .res 1

When I compile this:

#include <stdint.h>

int main()
{
    static volatile uint8_t x = 0;
    x = 1;
}

with 6502-gcc -O2 -S test.c -o-, again:

        ; ...
        .segment "CODE"
        .export main
main:
; frame size 0, pretend size 0, outgoing size 0
        lda #$01
        sta x$1365
        lda #$00
        sta _r0
        sta _r1
        rts
x$1365:
        .res 1

So it seems that happens to all variables with internal linkage. For some systems, that wouldn't be an issue, but for others the CODE segment resides in read-only memory.

I can manually fix that by using __attribute__((section("BSS"))) in every declaration, but I feel like that should be the default behavior.

PS: It seems x64 gcc 10.2 does that too.

Thanks for the detailed report! I thought I'd fixed this but apparently not... I'll have a look.

I have found one more thing which may be helpful.

#include <stdint.h>

static volatile uint8_t x = 0;
static volatile uint8_t y = 0;

int main()
{
    x = 1;
    y = 2;
}
        .segment "CODE"
        .export main
main:
; frame size 0, pretend size 0, outgoing size 0
        lda #$01
        sta x$
        lda #$02
        sta y$
        lda #$00
        sta _r0
        sta _r1
        rts
y$:
        .res 1
x$:
        .res 1
#include <stdint.h>

__attribute__((section("BSS"))) static volatile uint8_t x = 0;
static volatile uint8_t y = 0;

int main()
{
    x = 1;
    y = 2;
}
        .segment "CODE"
        .export main
main:
; frame size 0, pretend size 0, outgoing size 0
        lda #$01
        sta x$
        lda #$02
        sta y$
        lda #$00
        sta _r0
        sta _r1
        rts
y$:
        .res 1
        .segment "BSS"
x$:
.res 1,$00
#include <stdint.h>

static volatile uint8_t x = 0;
__attribute__((section("BSS"))) static volatile uint8_t y = 0;

int main()
{
    x = 1;
    y = 2;
}
        .segment "CODE"
        .export main
main:
; frame size 0, pretend size 0, outgoing size 0
        lda #$01
        sta x$
        lda #$02
        sta y$
        lda #$00
        sta _r0
        sta _r1
        rts
        .segment "BSS"
y$:
.res 1,$00
x$:
        .res 1
#include <stdint.h>

__attribute__((section("BSS"))) static volatile uint8_t x = 0;
__attribute__((section("BSS"))) static volatile uint8_t y = 0;

int main()
{
    x = 1;
    y = 2;
}
        .segment "CODE"
        .export main
main:
; frame size 0, pretend size 0, outgoing size 0
        lda #$01
        sta x$
        lda #$02
        sta y$
        lda #$00
        sta _r0
        sta _r1
        rts
        .segment "BSS"
y$:
.res 1,$00
x$:
.res 1,$00

I can confirm #9 fixes this.