Question about PROVIDE directive of linker script

I have been trying to re-implement xv6 in Rust.

In xv6's official C implementation, some global symbols are provided by the linker (linker script's PROVIDE directive) like following.

// in main.c

extern char end[];

// in kernel.ld

PROVIDE(end = .)

I understand that the linking processes are following.

  1. The linker searches the definition of end.

  2. There are no definition of end.

  3. The linker define the end symbol as the pointer that point the address . refers to.

And I tested the processes by the following way:

  1. Add PROVIDE(providing_test = 0xDEADBEEF) to kernel.ld.

  2. Add extern char providing_test[]; to main.c.

  3. Add cprintf("providing_test = %p\n", providing_test); to the main function of main.c.

  4. Run xv6 on QEMU.

As a result, providing_test = deadbeef was printed to the screen in fact.

Then, I tried the same test in Rust.

  1. Add PROVIDE(providing_test = 0xDEADBEEF) to kernel.ld.

  2. Add extern "C" { static providing_test: *const u8; } to

  3. Add println!("providing_test = {:p}", providing_test); to the main function of

  4. Run my kernel on QEMU.

When I try it, the VM was crushed (maybe because of the dereference of invalid pointer).

So, I examined what was happened, by objdumping the outputted kernel binary,
and I found that providing_test variable was putted on the address 0xDEADBEEF (not providing_test has the address 0xDEADBEEF).

Therefore, I changed my code to print the address of the variable providing_test,
and I got the correct result: providing_test = 0xdeadbeef was printed.

// changed code
    "providing_test = {:p}",
    &providing_test as *const (*const u8)

Now, I have a question: why does the Rust compiler put the variable on the PROVIDEed address ?
why not does it give the address to the variable as a content ?

Because my understandings about the Rust compiler and the linker are poor, I might misunderstand something or do some mistake.