Skip to content

Bug: "unable to evaluate constant expression" when depending on symbol address #6789

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ikskuh opened this issue Oct 24, 2020 · 13 comments
Closed
Labels
bug Observed behavior contradicts documented or intended behavior stage1 The process of building from source via WebAssembly and the C backend.
Milestone

Comments

@ikskuh
Copy link
Contributor

ikskuh commented Oct 24, 2020

Consider the following Zig code:

var stack: [256]u32 = undefined;

export const interrupt_table = [_][*]u32{
    @ptrCast([*]u32, &stack) + stack.len,
};

which will yield this error:

<source>:4:30: error: unable to evaluate constant expression
    @ptrCast([*]u32, &stack) + stack.len,
                             ^
<source>:3:41: note: referenced here
export const interrupt_table = [_][*]u32{
                                        ^

Such code is required when bootstrapping microcontrolls like the Cortex M3, as it requires the initial stack pointer to be stored in the interrupt vector table.

The C equivalent works:

uint32_t stack[256];

const uint32_t * interrupt_table[1] = {
    stack + 256,
};

Example in godbolt: https://c.godbolt.org/z/zhxcMM

One workaround i tried was declaring the end of stack as a separate symbol:

extern var stack: [256]u32;

export const interrupt_table = [_][*]u32{
    &stack,
};

but this yields this error:

<source>:4:5: error: unable to evaluate constant expression
    &stack,
    ^
<source>:3:41: note: referenced here
export const interrupt_table = [_][*]u32{
                                        ^

This code is required to work, otherwise it is not possible to bootstrap such microcontrollers in Zig.

@ghost
Copy link

ghost commented Oct 24, 2020

I wasn't aware that Zig allows pointer math? Don't you have to use ptrToInt?

@LiterallyVoid
Copy link
Contributor

Pointer math is allowed on unknown-length pointers ([*]T).

@ghost
Copy link

ghost commented Oct 24, 2020

Cool didn't know that. I guess that and intToPtr/ptrToInt are not currently allowed in a global expression.

The only workaround I got to work was making the stack 257 values long:

var stack: [257]u32 = undefined;

export const interrupt_table = [_][*]u32{
    @ptrCast([*]u32, &stack[256]),
};

@justinbalexander
Copy link
Contributor

@ikskuh
Copy link
Contributor Author

ikskuh commented Oct 24, 2020

@vegecode yeah, using linker script magic is a option here. for now, i just keep that part in C, doesn't really hurt. Can i somehow contact you on irc/discord/mail? I'd like to create some good embedded ARM base and it looks like you also did some work already :)

@justinbalexander
Copy link
Contributor

@MasterQ32, Sure you can contact me. I'm on reddit with the same username, I think discord too. I got burned out juggling family stuff, work, and side projects so I haven't done much in a while. I'd love to be re-inspired though! I can PM you my email on there which is probably the easiest way to get a response from me.

@andrewrk andrewrk added the bug Observed behavior contradicts documented or intended behavior label Oct 26, 2020
@andrewrk andrewrk added this to the 0.8.0 milestone Oct 26, 2020
@andrewrk andrewrk added the stage1 The process of building from source via WebAssembly and the C backend. label Oct 26, 2020
@andrewrk andrewrk modified the milestones: 0.8.0, 0.9.0 Nov 6, 2020
@andrewrk andrewrk modified the milestones: 0.9.0, 0.10.0 May 19, 2021
@iacore
Copy link
Contributor

iacore commented Apr 28, 2022

Does "address of symbol" even make sense with weak linkage?

For example, the address is not defined at compile time (of the object file), but will be defined when linked with other objects later.

Example

main.c:

#include <stdio.h>

extern __attribute__((weak)) int foo;

int main() {
    printf("%p\n", &foo);
    if (&foo != 0) {
        printf("foo = %d\n", foo);
    }
    fflush(stdout);
}

lib.c:

int foo = 42;
> clang -c main.c -o main.o^C
> clang main.o -o main
> ./main
(nil)
> clang -c lib.c -o lib.o
> clang main.o lib.o -o main2
> ./main2
0x5f732464c038
foo = 42

@Vexu
Copy link
Member

Vexu commented Apr 28, 2022

Why are you bringing up weak linkage? None of the symbols in the examples have weak linkage.

@iacore
Copy link
Contributor

iacore commented Apr 28, 2022

It is not in the example. I fear that some compiler/linker with attempt to move the PLT table after the zig code is already compiled (e.g. with compiler flags).

It is a concern for relocatable linkable objects too, where exported symbols can change address.

@SpexGuy
Copy link
Contributor

SpexGuy commented Apr 28, 2022

Regardless, it does still make sense. Comptime known addresses are symbolic values that will be resolved after comptime. They can be passed around and you can use @ptrToInt and @intToPtr on them, but attempting to inspect their actual value at comptime is a compile error. A more detailed description of how these symbols behave is in #9646.

It's implemented by tracking offsets and emitting relocations anywhere this value is stored.

@iacore
Copy link
Contributor

iacore commented Apr 28, 2022

If #9646 is implemented then it is fine.

@xdBronch
Copy link
Contributor

xdBronch commented Dec 8, 2023

this is marked stage1 and seems to compile now, can it be closed since stage2 is default?

@Vexu
Copy link
Member

Vexu commented Mar 28, 2024

Works in master.

@Vexu Vexu closed this as completed Mar 28, 2024
@Vexu Vexu modified the milestones: 0.15.0, 0.12.0 Mar 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Observed behavior contradicts documented or intended behavior stage1 The process of building from source via WebAssembly and the C backend.
Projects
None yet
Development

No branches or pull requests

8 participants