Re: Can not get struct member addresses at compile time

2021-06-17 Thread Doeme via Digitalmars-d-learn

On Wednesday, 16 June 2021 at 23:20:26 UTC, Ali Çehreli wrote:
Thank you, both. It still rules out an address at "compile 
time" in general. For example, we cannot use such an address 
when instantiating a template, or static array length, etc.


And if I understand it correctly, there must be a pointer 
*variable* for the linker to initialize. Fine then: That's how 
this usage works for C but not for D. :)


Thank you,
Ali


Yes, there must be a pointer variable, which explains why we can 
not do compile time pointer arithmetic, which is fair and square 
(although I think it might be possible with some extra compiler 
effort). It does _not_ explain why we can't take addresses of 
struct members, though, since we have a pointer variable there!


Coming back to the working part of my first example:

```d
struct Foo{
int bar;
}

__gshared Foo foo;
void *fooptr = &foo;
```

This works! And yields very similar relocations than the C 
version (plus some overhead and name-mangling):


```

[...]

  wO 
.data._D19TypeInfo_S4test3Foo6__initZ	0091 
_D19TypeInfo_S4test3Foo6__initZ

 g O .bss   0004 _D4test3Foo6__initZ
0004 g O .bss   0004 _D4test3fooSQk3Foo
 g   .tdata.0008 _D4test6fooptrPv
 g O .rodata	000d 
_D4test12__ModuleInfoZ


[...]

RELOCATION RECORDS FOR [.tdata.]:
OFFSET   TYPE  VALUE
 R_X86_64_64   _D4test3fooSQk3Foo

[...]

```

The only difference is that the compiler will not pass down 
relocations plus an offset (i.e. relocating to a member of a 
struct) down to the linker, and I don't quite see a specific 
reason why it should not.


Re: Can not get struct member addresses at compile time

2021-06-16 Thread Ali Çehreli via Digitalmars-d-learn

On 6/16/21 3:27 PM, Doeme wrote:

On Wednesday, 16 June 2021 at 22:16:54 UTC, H. S. Teoh wrote:
The compiler does not (and cannot) know.  But the runtime dynamic 
linker can, and does.  The two are bridged by the compiler emitting a 
relocatable symbol for the address of the global variable, with a 
table of relocations (offsets in the code) that the runtime linker 
patches the actual addresses into when the program is executed.



T


Exactly! Except that the dynamic linker is not really involved here, 
since all the symbols can/must be relocated statically at link time.


Thank you, both. It still rules out an address at "compile time" in 
general. For example, we cannot use such an address when instantiating a 
template, or static array length, etc.


And if I understand it correctly, there must be a pointer *variable* for 
the linker to initialize. Fine then: That's how this usage works for C 
but not for D. :)


Thank you,
Ali



Re: Can not get struct member addresses at compile time

2021-06-16 Thread Doeme via Digitalmars-d-learn

On Wednesday, 16 June 2021 at 22:16:54 UTC, H. S. Teoh wrote:
The compiler does not (and cannot) know.  But the runtime 
dynamic linker can, and does.  The two are bridged by the 
compiler emitting a relocatable symbol for the address of the 
global variable, with a table of relocations (offsets in the 
code) that the runtime linker patches the actual addresses into 
when the program is executed.



T


Exactly! Except that the dynamic linker is not really involved 
here, since all the symbols can/must be relocated statically at 
link time.


Re: Can not get struct member addresses at compile time

2021-06-16 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Jun 16, 2021 at 02:42:41PM -0700, Ali Çehreli via Digitalmars-d-learn 
wrote:
[...]
> Actually, it is news to me that the compiler can know (determine?) the
> address of a global variable.
[...]

The compiler does not (and cannot) know.  But the runtime dynamic linker
can, and does.  The two are bridged by the compiler emitting a
relocatable symbol for the address of the global variable, with a table
of relocations (offsets in the code) that the runtime linker patches the
actual addresses into when the program is executed.


T

-- 
War doesn't prove who's right, just who's left. -- BSD Games' Fortune


Re: Can not get struct member addresses at compile time

2021-06-16 Thread Doeme via Digitalmars-d-learn

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 

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:
 ldf *ABS*   test.c
 ld  .text   .text
 ld  .data.rel.local	 
.data.rel.local

 l O .data.rel.local0008 fooptr
0008 l O .data.rel.local0008 barptr
0010 l O .data.rel.local0008 bazptr
 ld  .rodata .rodata
 g O .bss   0008 foo
 g F .text  0070 main
 *UND*	 
_GLOBAL_OFFSET_TABLE_

 *UND*   printf

[...]

RELOCATION RECORDS FOR [.data.rel.local]:
OFFSET   TYPE  VALUE
 R_X86_64_64   foo
0008 R_X86_64_64   foo
0010 R_X86_64_64   foo+0x0004

[...]
```

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).




Re: Can not get struct member addresses at compile time

2021-06-16 Thread Ali Çehreli via Digitalmars-d-learn

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




Re: Can not get struct member addresses at compile time

2021-06-16 Thread Doeme via Digitalmars-d-learn

On Wednesday, 16 June 2021 at 11:56:31 UTC, Mike Parker wrote:

https://dlang.org/spec/pragma.html#crtctor


Very interesting, thanks for the hint! This is definitely a 
viable solution, though if there's a way to let the linker 
determine the pointer address, that'd be even better.


In C, it's a comparatively standard thing to do:

```c
struct Foo{
char bar;
};

struct Foo foo;
void *ptr = &foo.bar; //compiles, links and works
```

Why the D compilers would not pass this down to the linker eludes 
me.





Re: Can not get struct member addresses at compile time

2021-06-16 Thread Doeme via Digitalmars-d-learn

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...


Re: Can not get struct member addresses at compile time

2021-06-16 Thread Mike Parker via Digitalmars-d-learn

On Wednesday, 16 June 2021 at 13:26:43 UTC, jfondren wrote:



Is this a bug?


Probably. Please file an issue if there isn't one already:

https://issues.dlang.org/




Re: Can not get struct member addresses at compile time

2021-06-16 Thread Ali Çehreli via Digitalmars-d-learn

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:

struct Foo{
 ubyte bar;
 int i;
}

auto addrOf(T)(ref T t) {
  static struct AddrOf {
void * origin;
auto opDispatch(string member)() {
  return origin + mixin ("T." ~ member ~ ".offsetof");
}
  }
  return AddrOf(&t);
}

import std.stdio;

__gshared Foo foo;

void main() {
  writeln(&foo);

  writeln(foo.addrOf.bar);
  writeln(foo.addrOf.i);

  // Alternative syntax
  writeln(addrOf(foo).bar);
  writeln(addrOf(foo).i);
}

Ali



Re: Can not get struct member addresses at compile time

2021-06-16 Thread jfondren via Digitalmars-d-learn

On Wednesday, 16 June 2021 at 11:56:31 UTC, Mike Parker wrote:

https://dlang.org/spec/pragma.html#crtctor

"as a simple replacement for shared static this in betterC mode"

Cool.

However,

```d
immutable int example;

version(D_BetterC) {
pragma(crt_constructor) extern(C) void initialize() {
example = 1;
}
} else {
shared static this() {
example = 1;
}
}
```

this compiles without -betterC; with -betterC it errors out:

Error: cannot modify `immutable` expression `example`

Is this a bug?


Re: Can not get struct member addresses at compile time

2021-06-16 Thread Mike Parker via Digitalmars-d-learn

On Wednesday, 16 June 2021 at 09:27:25 UTC, Doeme wrote:

Is there an alternative to get to this point? Static module 
initializers are not really an option, since the whole thing 
should be -betterC.




```D
import core.stdc.stdio;
struct Foo{
 ubyte bar;
}

__gshared Foo foo;
void* baz = &foo;
void* bar;

extern(C):

pragma(crt_constructor)
void initialize() { bar = &foo.bar; }

void main()
{
*(cast(ubyte*)bar) = 10;
printf("%d", foo.bar);
}
```

https://dlang.org/spec/pragma.html#crtctor



Can not get struct member addresses at compile time

2021-06-16 Thread Doeme via Digitalmars-d-learn

Hi!

I'm currently investigating why I can not take the address of a 
static struct-element at compile time (afaik the linker should be 
able to resolve this, and doing the identical thing in C works...)


```d
struct Foo{
 ubyte bar;
}

__gshared Foo foo;
void* baz = \&foo;   //works
void* bar = \&foo.bar;   //Error: static variable `foo` cannot be 
read at compile time

```

Does this have to do with ".bar" potentially being a function 
call?

How does one get the address of a struct member?

The higher level problem of this question is that I want to make 
a pointer-map of a struct:


```d
import std.meta;
struct Foo{
ubyte a;
ushort b;
}

template ptrize(alias S){
enum ptrize =  \&S;
}

__gshared Foo f;
static immutable void*[] map = [staticMap!(ptrize, f.tupleof)];
```

Is there an alternative to get to this point? Static module 
initializers are not really an option, since the whole thing 
should be -betterC.


Thanks for any hints!