#cant convert ptr to int at comptime in zig but can in c

1 messages · Page 1 of 1 (latest)

stark hamlet
#
__attribute__((__aligned__(PGSIZE)))
pte_t entry_pgtable1[NPTENTRIES] = {};
__attribute__((__aligned__(PGSIZE)))
pte_t entry_pgtable2[NPTENTRIES] = {};


__attribute__((__aligned__(PGSIZE)))
pde_t entry_pgdir[NPDENTRIES] = {
    [0] = ((uint)entry_pgtable1) + PTE_P + PTE_W,
    [1] = ((uint)entry_pgtable2) + PTE_P + PTE_W,
};```
this is in a c file im converting to zig doing this:
```zig
var entry_pgtable1: [mmu.NPTENTRIES]mmu.pte_t align(mmu.PGSIZE) = std.mem.zeroes([mmu.NPDENTRIES]mmu.pde_t);
var entry_pgtable2: [mmu.NPTENTRIES]mmu.pte_t align(mmu.PGSIZE) = std.mem.zeroes([mmu.NPDENTRIES]mmu.pde_t);
var entry_pgdir: [mmu.NPDENTRIES]mmu.pde_t align(mmu.PGSIZE) = std.mem.zeroes([mmu.NPDENTRIES]mmu.pde_t);

comptime {
    entry_pgdir[0] = @as(u32, @intFromPtr(&entry_pgtable1)) + mmu.PTE_P + mmu.PTE_W;
    entry_pgdir[1] = @as(u32, @intFromPtr(&entry_pgtable2)) + mmu.PTE_P + mmu.PTE_W;
}

(this also fails to compile if they are = undefined instead of zeroes)

is c hiding the populations of the table somewhere? that seems unlikely

untold kraken
#

for now you can keep that part in c or initialize it at startup

stark hamlet
#

very cool

#

thank you so much

tiny dew
#

what are pde_t and pte_t? youre allowed to offset pointers just not convert them to ints

stark hamlet
#

u32

tiny dew
#

also regardless of intFromPtr or anything else the way youre trying to initialize it in that comptime block doesnt make much sense and will absolutely never work

#

what compiler are you using? that C code is not compilnig for me

a.c:18:42: error: initializer element is not a compile-time constant
   18 |     [0] = ((uint)entry_pgtable1) + PTE_P + PTE_W,
      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
#

it makes little sense that it would

untold kraken
#

if your target is 32 bit, you could probably make entry_pgdir be [][*]pde_t. if your target is 64 bit that won't work though

stark hamlet
#

yes imtargeting 32 bit

tiny dew
#

yeah this even being an int doesnt make sense to me

stark hamlet
#

zig cc -target x86-freestanding -mcpu=i386 -c main.c -o main.o -fno-sanitize=all

#

that was my compile line for when it was a c file

tiny dew
#

huh

untold kraken
tiny dew
#

everythings a define

#

wonder if it has to do with the int being pointer sized or something? I compiled it for x86_64 so the int is smaller

#

I really just wouldn't expect that to work

stark hamlet
#
#define PTE_P           0x001   // Present
#define PTE_W           0x002   // Writeable```

pub const PTE_P: u32 = 0x001;
pub const PTE_W: u32 = 0x002;```

#

in c and then in zig

untold kraken
# stark hamlet yes imtargeting 32 bit

oh then you can do it in zig

var entry_pgdir: [mmu.NPDENTRIES][*]mmu.pde_t align(mmu.PGSIZE) = .{
    &entry_pgtable[mmu.PTE_P..][mmu.PTE_W..],
    &entry_pgtable2[mmu.PTE_P..][mmu.PTE_W..],
};

similar to that

stark hamlet
#

im not doing pointer arithmetic or indexing

export fn main() void {
    entry_pgdir[0] = @as(u32, @intFromPtr(&entry_pgtable1)) | mmu.PTE_P | mmu.PTE_W;
    entry_pgdir[1] = @as(u32, @intFromPtr(&entry_pgtable2)) | mmu.PTE_P | mmu.PTE_W;
    ...
}```
this code works in the zig version. i would prefer it happens at comptime though
untold kraken
#

why is it + in C and | in zig?

stark hamlet
#

maybe the indexing is equivalent though

stark hamlet
untold kraken
#

indexing isn't quite equivalent because [1..] is equivalent to + 4 on []u32

#

so you might need to ptrcast to [*]u8 or something and then back to [*]u32

stark hamlet
#

hmmm

#

@as(u32, @intFromPtr(&entry_pgtable1)) + 3

#

so

tiny dew
#

no

#

no intFromPtr

stark hamlet
#

sorry i was figuring out the indexing and was going to post that

#

do i also have to case the table itself since it needs to be an int table later?

tiny dew
#

you can just cast the elements to ints when you need them

#

casting the array itself wont work for the same reason as the elements

stark hamlet
#
    const item1: [*]u8 = @ptrCast(&entry_pgtable1);
    entry_pgdir[0] = @as(u32, @intFromPtr(&item1[mmu.PTE_P | mmu.PTE_W]));
    const item2: [*]u8 = @ptrCast(&entry_pgtable2);
    entry_pgdir[1] = @as(u32, @intFromPtr(&item2[mmu.PTE_P | mmu.PTE_W]));```

this does have the right behavior so ill try comptime with a different type for the table
#

can i make something both *[4096]u8 and u32 without using the verbose union syntax?

#
comptime {
    const addr1: [*]u8 = @ptrCast(&entry_pgtable1);
    entry_pgdir[0] = @ptrCast(&addr1[mmu.PTE_P | mmu.PTE_W]);
    const addr2: [*]u8 = @ptrCast(&entry_pgtable2);
    entry_pgdir[1] = @ptrCast(&addr2[mmu.PTE_P | mmu.PTE_W]);
}```
#

this fails to compile

#
zig build-obj -target x86-freestanding -mcpu=i386 -I. main.zig -fno-stack-check -Drelease-fast -fPIC
main.zig:18:20: error: unable to evaluate comptime expression
    entry_pgdir[0] = @ptrCast(&addr1[mmu.PTE_P | mmu.PTE_W]);
    ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.zig:18:16: note: operation is runtime due to this operand
    entry_pgdir[0] = @ptrCast(&addr1[mmu.PTE_P | mmu.PTE_W]);
    ~~~~~~~~~~~^~~
main.zig:16:1: note: 'comptime' keyword forces comptime evaluation
comptime {
^~~~~~~~
referenced by:
    root: /opt/homebrew/Cellar/zig/0.14.0/lib/zig/std/start.zig:3:22
    comptime: /opt/homebrew/Cellar/zig/0.14.0/lib/zig/std/start.zig:27:9
    2 reference(s) hidden; use '-freference-trace=4' to see all references```
untold kraken
#

you can make union syntax less verbose with a decl literal to initialize it to the field you want

untold kraken
stark hamlet
#
    result[0] = .{ .ptr = @ptrCast(&@as([*]u8, @ptrCast(&entry_pgtable1))[mmu.PTE_P | mmu.PTE_W])``` };
#

apparently i cant do a union for the pointer anyway?

#
const pagetable = union { pointers: [mmu.NPDENTRIES]*[mmu.PGSIZE]u8, table: [mmu.NPDENTRIES]u32 };
var entry_pgdir: pagetable align(mmu.PGSIZE) = make_pdt: {
    var result: [mmu.NPDENTRIES]*[mmu.PGSIZE]u8 = undefined;
    result[0] = @ptrCast(&@as([*]u8, @ptrCast(&entry_pgtable1))[mmu.PTE_P | mmu.PTE_W]);
    result[1] = @ptrCast(&@as([*]u8, @ptrCast(&entry_pgtable2))[mmu.PTE_P | mmu.PTE_W]);
    break :make_pdt .{ .pointers = result };
};```
#

this totally solves the problem

#

any way to mark this thread as resolved

#

???

tiny dew
#

reinterpreting with a bare union is not valid

stark hamlet
#

not valid in what way?

tiny dew
#

its UB to access an inactive field

stark hamlet
#

std.debug.assert(@sizeOf(u32) == @sizeOf(*u8));
would this make you happier?

tiny dew
#

that is not the problem

stark hamlet
#

zig doesnt like type punning?

tiny dew
#

not with that type of union

#

theres extern union which matches C

stark hamlet
#

const pagetable = extern union { pointers: [NPDENTRIES]*[PGSIZE]u8, table: [NPDENTRIES]u32 };
is this well defined?

#

with my assert

tiny dew
#

yes

stark hamlet
#

is there a safe way to make a comptime pointer [*]u8 that stores address 0? it seems like i would have to use intToPtr or maybe another union?

tiny dew
#

should 0 be a valid address to access or just for the pointer to exist as

stark hamlet
#

0 is a valid address in this situation

tiny dew
#

[*]allowzero u8

stark hamlet
#

what do i put on the right hand side though

tiny dew
#

@ptrFromInt(0)

stark hamlet
#

thats ok at comptime?