Can not get struct member addresses at compile time

Doeme doeme at the-internet.org
Wed Jun 16 22:13:01 UTC 2021


On Wednesday, 16 June 2021 at 21:42:41 UTC, Ali Çehreli wrote:
> On 6/16/21 8:47 AM, Doeme wrote:
>
> > On Wednesday, 16 June 2021 at 13:36:07 UTC, Ali Çehreli wrote:
> >> On 6/16/21 2:27 AM, Doeme wrote:
> >>
> >> > How does one get the address of a struct member?
> >>
> >> Here is an experiment with offsetof and opDispatch:
> >
> > Cool stuff!
> > I actually tried a very similar approach once, but it did not
> work out,
> > since the D compilers refuse to do pointer arithmetic at
> compile time :/
> >
> > ```d
> > struct Foo{
> >   ubyte bar;
> > }
> >
> > void* membaddr(void *ptr, ulong offset){
> >      return ptr+offset;
> > }
> >
> > __gshared Foo foo;
> > void* bar = membaddr(&foo, foo.bar.offsetof);
> > //Error: cannot perform arithmetic on `void*` pointers at
> compile time
> > ```
> >
> > I guess that the opDispatch-method will suffer from the same
> issue...
>
> No, opDispatch does not work either for compile time addresses.
>
> Actually, it is news to me that the compiler can know 
> (determine?) the address of a global variable. I thought the 
> loador would determine the addresses, but apparently not. Is it 
> really a constant compiled value in the case of C? Can you show 
> an example please?
>
> Ali

The compiler can, in deed, not know the address, but the linker 
can.

Example:

```c
#include <stdio.h>

struct Foo{
	int bar;
	int baz;
};

struct Foo foo;
static const void *fooptr = &foo;
static const void *barptr = &foo.bar;
static const void *bazptr = &foo.baz;

int main(int argc, char **argv){
	printf("Address of foo: %p\n", fooptr); //Address of foo: 
0x55fbd8292030
	printf("Address of bar: %p\n", barptr); //Address of bar: 
0x55fbd8292030
	printf("Address of bau: %p\n", bazptr); //Address of bau: 
0x55fbd8292034
	return 0;
}

```

We can see that the code actually outputs the right addresses.

If we investigate the object file passed down to the linker, we 
see:

```
$ gcc -c test.c
$ objdump -x test.o

[...]

SYMBOL TABLE:
0000000000000000 l    df *ABS*	0000000000000000 test.c
0000000000000000 l    d  .text	0000000000000000 .text
0000000000000000 l    d  .data.rel.local	0000000000000000 
.data.rel.local
0000000000000000 l     O .data.rel.local	0000000000000008 fooptr
0000000000000008 l     O .data.rel.local	0000000000000008 barptr
0000000000000010 l     O .data.rel.local	0000000000000008 bazptr
0000000000000000 l    d  .rodata	0000000000000000 .rodata
0000000000000000 g     O .bss	0000000000000008 foo
0000000000000000 g     F .text	0000000000000070 main
0000000000000000         *UND*	0000000000000000 
_GLOBAL_OFFSET_TABLE_
0000000000000000         *UND*	0000000000000000 printf

[...]

RELOCATION RECORDS FOR [.data.rel.local]:
OFFSET           TYPE              VALUE
0000000000000000 R_X86_64_64       foo
0000000000000008 R_X86_64_64       foo
0000000000000010 R_X86_64_64       foo+0x0000000000000004

[...]
```

This tells us that:
* There are 3 variables in the initialized .data.rel.local 
section, our pointers.
* There is one variable in the zeroed .bss section, our instance 
of struct Foo
* To the positions of the of our three pointers in the 
.data.rel.local section, there is being written the address of 
the symbol foo, foo, and lastly, foo+4.

Thus, the address is only known at link time, but it _can_ be 
known by placing the right relocation commands to the object 
elf-file (i.e. relocation + offset, foo+4).



More information about the Digitalmars-d-learn mailing list