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