ghdl / ghdl

VHDL 2008/93/87 simulator
GNU General Public License v2.0
2.39k stars 363 forks source link

Second call of ghdl_main() aborts #1184

Open radonnachie opened 4 years ago

radonnachie commented 4 years ago

Description With a custom main(), the second call of ghdl_main(0, NULL) aborts the program.

Expected behaviour I expect to be able to resimulate. (Ultimately I want to pass in a different (argc, argv)/top-level generic the subsequent times - but I am not getting positive results passing in argc, argv in the first place. So that will be a second query.)

How to reproduce? Tell us how to reproduce this issue. Please provide a Minimal Working Example (MWE). With sample code it's easier to reproduce the bug and it's much faster to fix it. For example:

entity ent is
end entity;

architecture a of ent is
begin
  process begin
    report "Toplevel" severity note;
    wait;
  end process;
end;
extern int ghdl_main(char argc, char* argv[]);

int main(int argc, char const *argv[])
{
    for (size_t i = 0; i < 2; i++)
    {
        printf("ghdl_main return: %d\n", ghdl_main(0, NULL));
    }
    return 0;
}
gcc -c main.c
ghdl -a ent.vhd
ghdl -e -Wl,main.o bugtest
./bugtest

Context $ ghdl --version GHDL 0.36-dev (Ubuntu 0.35+git20181129+dfsg-4ubuntu1) [Dunoon edition] Compiled with GNAT Version: 8.3.0 llvm code generator

Additional context Just get the following in the terminal:

ent.vhd:7:16:@0ms:(report note): Toplevel
ghdl_main return: 0
./build.sh: line 5: 11322 Aborted                 (core dumped) ./bugtest
umarcor commented 4 years ago

@RocketRoss, for now, GHDL cannot be reset/restarted. You need to call the binary multiple times. If you are generating an ELF binary or shared library and loading it dynamically, you need to unload it from memory and load it again. See the following related issues: #1053, #803, #1059.

In VUnit/vunit#568 there is an example that shows how this is handled from Python. Precisely, see dlopen and dlclose in https://github.com/VUnit/vunit/pull/568/files#diff-14ddabc1969914ccb081e8cd8222616d

EDIT

So, for your case:

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

//extern int ghdl_main(char argc, char* argv[]);

int main(int argc, char const *argv[])
{
    typedef int main_t(int, char**);

    for (size_t i = 0; i < 2; i++)
    {
        void * h = dlopen("path/to/ghdl/generated/binary",  RTLD_LAZY);
        main_t *ghdl_main = (main_t*)dlsym(h, "ghdl_main");
        if (!ghdl_main){
            fprintf(stderr, "%s\n", dlerror());
            exit(2);
        }
        printf("ghdl_main return: %d\n", ghdl_main(0, NULL));
        dlclose(h);
    }
    return 0;
}

Note that, as a trick, the ELF binaries generated by ghdl -e with LLVM can be loaded as shared libraries. This is hackish, but it works (on GNU/Linux). If you want to do it "properly", use --bind and --list-link with GCC to generate an *.so file, instead of ghdl -e.

radonnachie commented 4 years ago

@umarcor, Thanks for taking the time to write such an informative response. I'll run through the links etc.

By "path/to/generated/binary" d'you mean the toplevel from ghdl -a ... && ghdl -e ...?

I suspect that either way this ought to be closed. Unless there is a possibility of adding a reset function to the feature request list. (Excuse me if I'm treating a complex issue as a far simpler one.)

umarcor commented 4 years ago

@umarcor, Thanks for taking the time to write such an informative response. I'll run through the links etc.

This is a not-very-used feature of GHDL. It's always a pleasure to share knowledge with other users in this niche! Be aware that some of the content might be interesting for you, as a user of VHPIDIRECT. Not specific about this issue.

By "path/to/generated/binary" d'you mean the toplevel from ghdl -a ... && ghdl -e ...?

I mean the (executable) file that you get as the artifact of your design. If you use mcode backend, such artifact does not exist. mcode is an in-memory backend, so you cannot dlopen it. With LLVM backend, the name of the binary is typically the toplevel. In your example above, ./ent (shouldn't the entity in your MWE need to be bugtest so that you get a binary named like that?). However, note that this might change:

ghdl -a ent.vhd
#ghdl -e -Wl,main.o bugtest
ghdl --bind bugtest
gcc -fPIC -rdynamic -shared wrapper.c -Wl,`ghdl --list-link bugtest` -o name_you_want.so

gcc main.c -o main

Note that:

See https://ghdl.readthedocs.io/en/latest/using/Foreign.html#linking-ghdl-to-ada-c

Further notes:

I suspect that either way this ought to be closed.

I think it is ok to keep it open. AFAIK, there is no specific issue to request the feature of "being able to reset GHDL in-memory". I believe that this alone might be faster to be implemented than other features mentioned in #1053, such as run_until.

Unless there is a possibility of adding a reset function to the feature request list.

The meaning of ghdl_restart in the quoted text in #1053 is the same as this request of yours.

(Excuse me if I'm treating a complex issue as a far simpler one.)

According to Tristan, this is not complex. However, I tried and I could not do it. Maybe you are luckier :D. Anyway, I understand that this is a low priority issue for now. Synthesis and supporting VHDL 2008 features are more demanded features!

radonnachie commented 4 years ago

Ah of course, I'd understand pushing support for VHDL 2008 over this. I think that features of this sort will create really powerful tools in the simulation on top of GHDL.

(shouldn't the entity in your MWE need to be bugtest so that you get a binary named like that?) Yup, I was cutting corners on the form! Well spotted.

Do you mind helping a bit further: I'm trying to set up the mentioned shared library and PIE.

Let me share my context: I built ghdl-llvm with --default-pic in anticipation for this sort of work. So far it hasn't been useful: apt-get install ghdl-llvm has worked everytime. I dont know when to use the -Wl,-pie compilation flag though.... On that, my compilation understanding seems to be slipping: I came up with:

ghdl-gcc -a BugTest.vhd &&
ghdl-gcc --bind bugtest &&
gcc main.c -Wl,`ghdl-gcc --list-link bugtest` &&
./a.out &&
rm *.o work-obj93.cf a.out

for your

ghdl-gcc -a bugtest.vhd ghdl-gcc --bind bugtest gcc -fPIC -rdynamic -shared wrapper.c -Wl,ghdl-gcc --list-link bugtest -o name_you_want.so gcc main.c -o main

Yours fails with:

/usr/bin/ld: /usr/lib/ghdl/gcc/vhdl/libgrt.a(grt-cbinding.o): relocation R_X86_64_PC32 against symbol `stdout@@GLIBC_2.2.5' can not be used when making a shared object; recompile with -fPIC

What do you suspect needs recompilation with the '-fPIC' flag? GLIBC? GHDL-gcc? This sort of thing escapes me.

According to Tristan, this is not complex. However, I tried and I could not do it. Maybe you are luckier :D.

Life goals right there. I'll keep working towards it :+1:

EDIT Clean up markup.

umarcor commented 4 years ago

I think that features of this sort will create really powerful tools in the simulation on top of GHDL.

I do believe so. Apart from dbhi.github.io and VUnit/cosim, see the screencasts in VUnit/vunit#568. That's a simulation GUI written in Vue, with a Flask backend that loads a GHDL simulation dynamically. It allows to build "custom virtual boards and interactive testbenches". Of course, it is just a fancy proof of concept for now.

Let me share my context: I built ghdl-llvm with --default-pic in anticipation for this sort of work.

Precisely, images in dbhi/docker use GHDL with LLVM backend and --default-pic.

So far it hasn't been useful: apt-get install ghdl-llvm has worked everytime. I dont know when to use the -Wl,-pie compilation flag though.... On that, my compilation understanding seems to be slipping

TBH, I am neither sure about when are -fPIC, -PIE and/or -rdynamic required. For GCC, I put all three and then remove them one by one.

I do know that GHDL tried to detect --default-pic from the system. If the system GCC and libs were compiled with fPIC/PIE, it did compile all the libs with it. When GHDL is configured with --default-pic explicitly, it is supposed to use it implicitly when executing any -a, -e or -r command. Hence, you do never need to provide these arguments (fPIC/PIE) to ghdl, as long as you use a recent version of GHDL and you configure it properly.

/usr/bin/ld: /usr/lib/ghdl/gcc/vhdl/libgrt.a(grt-cbinding.o): relocation R_X86_64_PC32 against symbol `stdout@@GLIBC_2.2.5' can not be used when making a shared object; recompile with -fPIC

What do you suspect needs recompilation with the '-fPIC' flag? GLIBC? GHDL-gcc? This sort of thing escapes me.

It seems that the version of GHDL that you have does NOT use fPIC by default. When it was built, libgrt.a was compiled without it. Hence, it fails to link it with a wrapper.o or main.o which is position independent. I would say that the ./a.out that you get is not PIE. That is, you can execute it in the CLI but you cannot load it dynamically. Moreover, if you add -shared to your gcc call, it should fail.

Hence, you do need a version of GHDL that was built with --default-pie, so that libgrt.a and all the std and ieee libs are PIE. If you don't want to build GHDL yourself, any of the docker/podman images in the following repos should work for you: ghdl/ghdl, ghdl/vunit or aptman/dbhi.

Also, sooner or later, this conversation will be interesting/useful for you: #800

Life goals right there. I'll keep working towards it 👍

I pointed you to some sources in the other issue, so that you can have a glance at them.

radonnachie commented 4 years ago

I've gotten further but am still struggling to dlopen() dlclose() the symbol of ghdl_main.

I just get cannot dynamically load position-independent executable on trying to open the output from -e or --list-link. The posts I have read are a little hazy on when you can/not dlopen() a Position independent executable.

Any further pointers @umarcor? When I have got this down, it'll be noted in the examples (#1059 comment


As a foot note on the build process, my attempts were:

#gcc
ghdl-gcc -a BugTest.vhd &&
ghdl-gcc --bind bugtest &&
gcc wrapper.c -fPIC -rdynamic -Wl,`ghdl-gcc --list-link bugtest` -o bugtest.so
gcc -o main main.c -ldl &&
./main

#llvm
#/etc/ghdl-llvm-non-PIC-compiled/bin/ghdl -a BugTest.vhd &&
#/etc/ghdl-llvm-non-PIC-compiled/bin/ghdl -e bugtest
#gcc -o main main.c -ldl &&
#./main

#llvm --bind
#gcc
#/etc/ghdl-llvm-non-PIC-compiled/bin/ghdl -a BugTest.vhd &&
#/etc/ghdl-llvm-non-PIC-compiled/bin/ghdl --bind bugtest &&
#gcc wrapper.c -fPIC -rdynamic -Wl,`/etc/ghdl-llvm-non-PIC-compiled/bin/ghdl --list-link bugtest` -o bugtest.so
#gcc -o main main.c -ldl &&
#./main
umarcor commented 4 years ago

@RocketRoss you are generating an executable ELF binary, not an ELF shared library. Naming it *.so won't change that; I believe you need to add -shared as an argument to GCC. Sometimes, an executable ELF can be dynamically loaded, but the proper way is for it to be a shared lib. Actually, that's the main reason to use GCC explicitly, instead of ghdl -e.

radonnachie commented 4 years ago

Grand, I used ghdl-llvm (one compiled with -fPIC) and the -shared flag, following the #gcc process - it produced a .so (shared object this time) which was happily gobbled by dlopen().... only to find no symbol for ghdl_main... further thoughts? I have this C code (copied yours, but now you dont have to scroll for it):

typedef int main_t(int, char**);
void * h = dlopen("./bugtest.so",  RTLD_LAZY);
printf("dlerror() after dlopen: '%s'\n", dlerror());
main_t *ghdl_main = (main_t*)dlsym(h, "ghdl_main");
if (!ghdl_main){
  fprintf(stderr, "%s\n", dlerror());
  exit(2);
}
printf("ghdl_main return: %d\n", ghdl_main(0, NULL));
dlclose(h);
umarcor commented 4 years ago

By default, GHDL uses grt.ver to limit which symbols are exposed:

ANY {
  global:
vpi_chk_error;
vpi_control;
vpi_free_object;
vpi_get;
vpi_get_str;
vpi_get_time;
vpi_get_value;
vpi_get_vlog_info;
vpi_handle;
vpi_handle_by_index;
vpi_handle_by_name;
vpi_iterate;
vpi_mcd_close;
vpi_mcd_name;
vpi_mcd_open;
vpi_put_value;
vpi_register_cb;
vpi_register_systf;
vpi_remove_cb;
vpi_scan;
vpi_vprintf;
vpi_printf;
  local:
        *;
};

As you see, ghdl_main is not in the list. You need to either avoid the version script (so that all symbols are visible) or you need to provide a custom one. See #800, referenced above. See also the hint in https://ghdl.readthedocs.io/en/latest/using/CommandReference.html#list-link-list-link. For example, this one is used in VUnit/cosim: https://github.com/VUnit/cosim/blob/master/cosim/vhpidirect/c/grt.ver.

Note that, when using VHPIDIRECT, you don't need any of those vpi* functions to be exposed. That's why VUnit/cosim just ignores them.

radonnachie commented 4 years ago

Sorry, you had actually given me all the resources to get to where I am now from the get go. I think I got a little lost on the way (losing the -shared flag, and not seeing the relevance of #800).

I have tried to be more thorough this time. But again I am stuck. (I am explaining my understanding too in case there is an error there)

The --version-script flag is meant for elaboration. But in order to generate a shared object (not an executable) of the ghdl simulation, we replace ghdl -e with ghdl --bind, then we create a manual compilation of the SO with a gcc -shared -fPIC call that uses the ghdl --list-link. (The -Wl,ghdl --list-link... feeds extra linking options to the linker invoked by gcc [right?]j). As the --list-link is the second half of the -e step, I added the --version-script option to it. I have copied the VUnit grt.ver, and point to it.

I do use a ghdl-llvm that was compiled with --default-pic. It is necessary, as stated a few times already.

Compilation happens, without errors. But at run time dlsym() still doesn't find ghdl_main.


I dont use the empty wrapper.c file in the SO gcc compilation, it doesnt make a difference if I do.. I dont compile main with the SO, it doesnt make a difference if I do. I do compile main with -ldl for the dl*() functions. I use the same ghdl in every related call, so there is no mixing of grt.ver/backend stuff.


I wondered if this has to do with the custom grt.ver being exposed as VHPIDIRECT, and me needing to change the symbol I search for.


I am struggling to apply all of the comments and solutions across the threads that mention this because of the very different compilation processes.

I even sat for a while working out where one would use ghdl -e -Wl,-shared in this, as per #800 comment.. I feel like it doesn't fit in to this process, even though it seems to have come up while @umarcor was dealing with my comments.


The code again:

entity BugTest is
end entity BugTest;

architecture RTL of BugTest is
begin
    process
    begin
        report "Toplevel";
        wait;
    end process;
end architecture RTL;
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{
    typedef int main_t(int, char**);

    for (size_t i = 0; i < 3; i++)
    {
        void * h = dlopen("./ghdl.so",  RTLD_LAZY);
        printf("dlerror() after dlopen: '%s'\n", dlerror());
        main_t *ghdl_main = (main_t*)dlsym(h, "ghdl_main");
        if (!ghdl_main){
            fprintf(stderr, "%s\n", dlerror());
            exit(2);
        }
        printf("ghdl_main return: %d\n", ghdl_main(0, NULL));
        dlclose(h);
    }
    return 0;
}
/etc/ghdl-llvm-PIC-compiled/bin/ghdl -a BugTest.vhd 
/etc/ghdl-llvm-PIC-compiled/bin/ghdl --bind bugtest 
gcc -fPIC -rdynamic -shared -Wl,`/etc/ghdl-llvm-PIC-compiled/bin/ghdl --list-link -Wl,-Wl,--version-script=/etc/ghdl-llvm-PIC-compiled/grt.ver bugtest` -o ghdl.so
gcc main.c -ldl -o main &&
./main
tgingold commented 4 years ago

If the ghdl_main symbol is missing, maybe you should force it to be added by linking with -Wl,-u,ghdl_main (or maybe -Wl,-Wl,-u,ghdl_main)

umarcor commented 4 years ago

Sorry, you had actually given me all the resources to get to where I am now from the get go. I think I got a little lost on the way (losing the -shared flag, and not seeing the relevance of #800).

It's ok. As you are seeing, almost all the details are directly or indirectly documented already; hence, potentially you already have all the resources that you might need. However, the content is not friendly to new users; it is rather meant as a reference/cheatsheet for those who already know the big picture. That's the gap we are trying to narrow!

I have tried to be more thorough this time. But again I am stuck. (I am explaining my understanding too in case there is an error there)

All your explanations seem ok. It feels to me that the issues you are facing now are not strictly related to GHDL. Let's step back a bit. I uploaded https://github.com/umarcor/ghdl-cosim/tree/master/dlopen. Can you execute run.sh? I tried it in a docker container (aptman/dbhi:bionic) and the output is the following:

root@d7c2c81c52f6:/src/dlopen# ./run.sh
Build corea.so
Build coreb.so
Build main
Test
> Hello, I'm your host: 29
> Hello, I'm core A
> Hello, I'm core B

As you can see, it just builds two dummy ghdl_main functions in separate shared libs. Then, both of them are dynamically loaded at the same time in the main application, and both are executed (one after the other).

If the symbol is still not found, try adding -g and/or -rdynamic when building corea.so and coreb.so. Actually, it'd be useful if you added them to corea.so only, so you can tell the difference.

Honestly, I am not sure about the rules to make symbols visible. Depending on the platform/board, sometimes symbols are visible by default, sometimes you need additional flags, sometimes there is no way... Precisely, I found the example above to fail on boards with older versions of GCC (4? 5?). Unfortunately, I did not find how to make it work consistently accross a wide variety of platforms. That's why, if possible, I try to use Docker (even on SBCs).

Precisely, dbhi/binhook is an attempt to gather different techniques for hijacking/replacing a given function in a pre-built binary/library. That's out of scope for us, because we do have access to the sources of the binary/library that we want to load/execute. However, it is related in the sense that all those techniques do need to somehow (elegant or ugly) find the symbol in order to have it replaced. As a matter of fact, I've been working on combining such function replacement techniques with GHDL and VUnit (see https://dbhi.github.io/pdf/FPGA2020_poster.pdf).

  • I try the objdump -d ghdl.so | grep "<ghdl_main>" from #640. I tried on a number of objects nothing is found to match.... But there was a different build process in that issue.

This is relevant. You need to be able to see the symbol anyhow (objdump, readelf, nm, etc.). For example:

root@d7c2c81c52f6:/src/dlopen# objdump -d corea.so 

corea.so:     file format elf64-x86-64

Disassembly of section .init:

00000000000004e8 <_init>:
 4e8:   48 83 ec 08             sub    $0x8,%rsp
 4ec:   48 8b 05 f5 0a 20 00    mov    0x200af5(%rip),%rax        # 200fe8 <__gmon_start__>        
 4f3:   48 85 c0                test   %rax,%rax
 4f6:   74 02                   je     4fa <_init+0x12>
 4f8:   ff d0                   callq  *%rax
 4fa:   48 83 c4 08             add    $0x8,%rsp
 4fe:   c3                      retq

Disassembly of section .plt:

0000000000000500 <.plt>:
 500:   ff 35 02 0b 20 00       pushq  0x200b02(%rip)        # 201008 <_GLOBAL_OFFSET_TABLE_+0x8>  
 506:   ff 25 04 0b 20 00       jmpq   *0x200b04(%rip)        # 201010 <_GLOBAL_OFFSET_TABLE_+0x10> 50c:   0f 1f 40 00             nopl   0x0(%rax)

0000000000000510 <puts@plt>:
 510:   ff 25 02 0b 20 00       jmpq   *0x200b02(%rip)        # 201018 <puts@GLIBC_2.2.5>
 516:   68 00 00 00 00          pushq  $0x0
 51b:   e9 e0 ff ff ff          jmpq   500 <.plt>

Disassembly of section .plt.got:

0000000000000520 <__cxa_finalize@plt>:
 520:   ff 25 d2 0a 20 00       jmpq   *0x200ad2(%rip)        # 200ff8 <__cxa_finalize@GLIBC_2.2.5> 526:   66 90                   xchg   %ax,%ax

Disassembly of section .text:

0000000000000530 <deregister_tm_clones>:
 530:   48 8d 3d f1 0a 20 00    lea    0x200af1(%rip),%rdi        # 201028 <_edata>
 537:   55                      push   %rbp
 538:   48 8d 05 e9 0a 20 00    lea    0x200ae9(%rip),%rax        # 201028 <_edata>
 53f:   48 39 f8                cmp    %rdi,%rax
 542:   48 89 e5                mov    %rsp,%rbp
 545:   74 19                   je     560 <deregister_tm_clones+0x30>
 547:   48 8b 05 92 0a 20 00    mov    0x200a92(%rip),%rax        # 200fe0 <_ITM_deregisterTMCloneTable>
 54e:   48 85 c0                test   %rax,%rax
 551:   74 0d                   je     560 <deregister_tm_clones+0x30>
 553:   5d                      pop    %rbp
 554:   ff e0                   jmpq   *%rax
 556:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
 55d:   00 00 00
 560:   5d                      pop    %rbp
 561:   c3                      retq
 562:   0f 1f 40 00             nopl   0x0(%rax)
 566:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
 56d:   00 00 00

0000000000000570 <register_tm_clones>:
 570:   48 8d 3d b1 0a 20 00    lea    0x200ab1(%rip),%rdi        # 201028 <_edata>
 577:   48 8d 35 aa 0a 20 00    lea    0x200aaa(%rip),%rsi        # 201028 <_edata>
 57e:   55                      push   %rbp
 57f:   48 29 fe                sub    %rdi,%rsi
 582:   48 89 e5                mov    %rsp,%rbp
 585:   48 c1 fe 03             sar    $0x3,%rsi
 589:   48 89 f0                mov    %rsi,%rax
 58c:   48 c1 e8 3f             shr    $0x3f,%rax
 590:   48 01 c6                add    %rax,%rsi
 593:   48 d1 fe                sar    %rsi
 596:   74 18                   je     5b0 <register_tm_clones+0x40>
 598:   48 8b 05 51 0a 20 00    mov    0x200a51(%rip),%rax        # 200ff0 <_ITM_registerTMCloneTable>
 59f:   48 85 c0                test   %rax,%rax
 5a2:   74 0c                   je     5b0 <register_tm_clones+0x40>
 5a4:   5d                      pop    %rbp
 5a5:   ff e0                   jmpq   *%rax
 5a7:   66 0f 1f 84 00 00 00    nopw   0x0(%rax,%rax,1)
 5ae:   00 00
 5b0:   5d                      pop    %rbp
 5b1:   c3                      retq
 5b2:   0f 1f 40 00             nopl   0x0(%rax)
 5b6:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
 5bd:   00 00 00

00000000000005c0 <__do_global_dtors_aux>:
 5c0:   80 3d 61 0a 20 00 00    cmpb   $0x0,0x200a61(%rip)        # 201028 <_edata>
 5c7:   75 2f                   jne    5f8 <__do_global_dtors_aux+0x38>
 5c9:   48 83 3d 27 0a 20 00    cmpq   $0x0,0x200a27(%rip)        # 200ff8 <__cxa_finalize@GLIBC_2.2.5>
 5d0:   00
 5d1:   55                      push   %rbp
 5d2:   48 89 e5                mov    %rsp,%rbp
 5d5:   74 0c                   je     5e3 <__do_global_dtors_aux+0x23>
 5d7:   48 8b 3d 42 0a 20 00    mov    0x200a42(%rip),%rdi        # 201020 <__dso_handle>
 5de:   e8 3d ff ff ff          callq  520 <__cxa_finalize@plt>
 5e3:   e8 48 ff ff ff          callq  530 <deregister_tm_clones>
 5e8:   c6 05 39 0a 20 00 01    movb   $0x1,0x200a39(%rip)        # 201028 <_edata>
 5ef:   5d                      pop    %rbp
 5f0:   c3                      retq
 5f1:   0f 1f 80 00 00 00 00    nopl   0x0(%rax)
 5f8:   f3 c3                   repz retq
 5fa:   66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)

0000000000000600 <frame_dummy>:
 600:   55                      push   %rbp
 601:   48 89 e5                mov    %rsp,%rbp
 604:   5d                      pop    %rbp
 605:   e9 66 ff ff ff          jmpq   570 <register_tm_clones>

000000000000060a <ghld_main>:
 60a:   55                      push   %rbp
 60b:   48 89 e5                mov    %rsp,%rbp
 60e:   48 83 ec 10             sub    $0x10,%rsp
 612:   89 7d fc                mov    %edi,-0x4(%rbp)
 615:   48 89 75 f0             mov    %rsi,-0x10(%rbp)
 619:   48 8d 3d 15 00 00 00    lea    0x15(%rip),%rdi        # 635 <_fini+0x9>
 620:   e8 eb fe ff ff          callq  510 <puts@plt>
 625:   b8 00 00 00 00          mov    $0x0,%eax
 62a:   c9                      leaveq
 62b:   c3                      retq

Disassembly of section .fini:

000000000000062c <_fini>:
 62c:   48 83 ec 08             sub    $0x8,%rsp
 630:   48 83 c4 08             add    $0x8,%rsp
 634:   c3                      retq
  • I dont know what the e~bugtest.o object is for...

I believe this is why you need to call ghdl --bind. See #781.

I am struggling to apply all of the comments and solutions across the threads that mention this because of the very different compilation processes.

This might be, partially, my fault. As commented in https://github.com/ghdl/ghdl/issues/800#issuecomment-610602607, I thought that using GCC, --bind and --list-link was compulsory in order to generate a shared library. But it seems not to be true. Hence, I should start testing and using ghdl -e only (as it feel much easier).

I even sat for a while working out where one would use ghdl -e -Wl,-shared in this, as per #800 comment.. I feel like it doesn't fit in to this process, even though it seems to have come up while @umarcor was dealing with my comments.

It does. Instead of:

ghdl-gcc --bind bugtest &&
gcc wrapper.c -fPIC -shared -Wl,`ghdl-gcc --list-link bugtest` -Wl,--version-script=file.ver -o bugtest.so

the following should work:

gcc -c -fPIC wrapper.c &&
ghdl -e -Wl,wrapper.o -Wl,-shared -Wl,-Wl,--version-script=file.ver -o bugtest.so bugtest

However, I did not test it yet.

radonnachie commented 4 years ago

-Wl,-Wl,-u,ghdl_main

^^ has helped where -Wl,-Wl,--version-script=/etc/ghdl-llvm-PIC/grt.ver could not In each following code block, the first line works, the others (all beginning with a #) do not:

/etc/ghdl-llvm-PIC/bin/ghdl -e -Wl,-shared -Wl,-Wl,-u,ghdl_main -o ghdl.so bugtest
#/etc/ghdl-llvm-PIC/bin/ghdl -e -Wl,-shared -Wl,-Wl,--version-script=cust.ver -o ghdl.so bugtest
gcc -fPIC -shared -Wl,`/etc/ghdl-llvm-PIC/bin/ghdl --list-link -Wl,-Wl,-u,ghdl_main bugtest` -o ghdl.so
#gcc -fPIC -shared -Wl,`/etc/ghdl-llvm-PIC/bin/ghdl --list-link bugtest` -Wl,--version-script=cust.ver -o ghdl.so
#gcc -fPIC -shared -Wl,`/etc/ghdl-llvm-PIC/bin/ghdl --list-link -Wl,-Wl,--version-script=cust.ver bugtest` -o ghdl.so

So I am having issues with using the --version-script

tgingold commented 4 years ago

The version script is required to support vpi, but by default symbols are exported when building a shared library.

So I think you need the -u ghdl_main. You may add the version script (or not), but that's not required. I suppose if you add the version script you must also export ghdl_main.

umarcor commented 4 years ago

The version script is required to support vpi, but by default symbols are exported when building a shared library.

I'm not sure about this. I believe that GHDL uses grt.ver by default, even if VPI is not being used. Hence, all symbols except the ones defined in grt.ver are hidden. That's why:

https://github.com/ghdl/ghdl/issues/640#issuecomment-486433605

I think it would still be useful to have a --no-version-script as an option to --list-link.

Now, I'd add that it would be useful to have it as an argument to ghdl -e too.

In fact, this was the motivation for #801. Since the default version script cannot be removed (without using sed to parse the output of --list-link), it was made compatible with additional version scripts. Theoretically, that allows users to provide a list of symbols, apart from the defaults made visible by grt.ver. That's how I've been using it.

So I think you need the -u ghdl_main. You may add the version script (or not), but that's not required.

In order to expose ghdl_main only, this is correct. However, for exposing multiple symbols (such as the ones in ghdl.h) it is cumbersome to provide all of them in the CLI. That's why I think that @RocketRoss should try to guess how to use a custom version script.

I suppose if you add the version script you must also export ghdl_main.

Indeed. All the custom version scripts I use do include ghdl_main, at least.

@RocketRoss, did you try the dlopen example? What's the output of objdump -d corea.so?

radonnachie commented 4 years ago

@umarcor Your dlopen worked out of the box, it helped confirm my understanding of what is going on. Thanks for it.

I suppose if you add the version script you must also export ghdl_main.

I believe I am trying to export ghdl_main with the custom.ver file (as I said I borrowed it from VUnit: first 4 lines:

VHPIDIRECT {
  global:
main;
ghdl_main;
...
local:
*;
};

Now, I'd add that it would be useful to have it as an argument to ghdl -e too.

Now it seems as though the --version-script option hasn't actually made its way to my ghdl?? But it had been merged in #801.

I think it would still be useful to have a --no-version-script as an option to --list-link.

It didn't work in my --list-link either. So how come some are using it and I am not. Mistook --no-version-script for --version-script.

Edit: ghdl version

GHDL 1.0-dev (v0.37.0-178-gbe59edef) [Dunoon edition] Compiled with GNAT Version: 8.3.0 llvm code generator

umarcor commented 4 years ago

@umarcor Your dlopen worked out of the box, it helped confirm my understanding of what is going on. Thanks for it.

Good! That means that we need to guess what's happening with GHDL, but the system tools are ok.

Now, I'd add that it would be useful to have it as an argument to ghdl -e too.

Now it seems as though the --version-script option hasn't actually made its way to my ghdl?? But it had been merged in #801.

This is interesting... what's the content of your default grt.ver file? You can get the path from --list-link.

I think it would still be useful to have a --no-version-script as an option to --list-link.

It didn't work in my --list-link either. So how come some are using it and I am not. Will edit with my ghdl version details again.

This might be a misunderstanding. --no-version-script was never implemented, neither for --list-link nor for -e. I'm actually requesting/asking Tristan whether he'd consider to add this feature.

Anyway, we should be able to fix your issue regardless of that option being supported.

In fact, I did not ignore umarcor/ghdl#1, but I did not reply yet because I'm working on https://github.com/umarcor/ghdl-cosim/tree/todo. See https://umarcor.github.io/ghdl-cosim/. That's a refactorisation/extension of https://ghdl.readthedocs.io/en/latest/using/Foreign.html. The interesting difference is that several examples are included:

quickstart/random,
quickstart/math,
quickstart/customc,
linking/*,
wrapping/basic,
wrapping/time,
accarray/*,
demo,
shlib/dlopen,
shlib/ghdl

It is basically a remix of the references in https://github.com/eine/hwd-ide/tree/develop/examples/VHPI and the multiple tests that you did during this last week. However, it is not ready yet. Please, let me finish adding (specially, setting up the CI for shlib/ghdl, which is the example that corresponds to your current issue) and tidying it up. I will let you know when it's ready, since I'd like to rebase umarcor/ghdl#1 on top of it, instead of the fork of this repo. Actually, example accarray is a placeholder for your "C access" example.

radonnachie commented 4 years ago

It gets interesting! Because (luckily) I hadn't cleaned up some experiments:

This is interesting... what's the content of your default grt.ver file?

The default grt.ver file actually had ghdl_main; listed under global. I had put it there in exasperation a while back. Having removed it, the executable compilation lines above no longer work. These:

/etc/ghdl-llvm-PIC/bin/ghdl -e -Wl,-shared -Wl,-Wl,-u,ghdl_main -o ghdl.so bugtest
#or
gcc -fPIC -shared -Wl,`/etc/ghdl-llvm-PIC/bin/ghdl --list-link -Wl,-Wl,-u,ghdl_main bugtest` -o ghdl.so

The objdump of the SO does contain the <ghdl_main> definition though. But still such a symbol is not found by dlsym().

Of course then, adding -Wl,-Wl,--version-script=custom.ver in with the -Wl,-Wl,-u,ghdl_main gets the -e and gcc generated SOs to work.

So now the question is, why do I have to provide a custom.ver file and -u expose the function. I do think this is what Tristan meant though, that I have to do both.


In fact, I did not ignore umarcor#1, but I did not reply yet because I'm working

I like the sound of it. Will be glad to help once you're ready for it. I'll double check the hwd-ide examples out in the meanwhile.

tgingold commented 4 years ago

I have just added the '-shared' option. It removes the version script. I have just quickly tested it, so maybe it has to be tuned. In particular, we may need to also add the -u ghdl_main option.

radonnachie commented 4 years ago

Confirming that I got the -shared elaboration flag to generate a SO file with the toplevel entity's name. Still needed to expose ghdl_main.

/etc/ghdl-llvm-PIC/bin/ghdl -a Bugtest.vhd &&
/etc/ghdl-llvm-PIC/bin/ghdl -e -shared -Wl,-Wl,-u,ghdl_main Bugtest &&
gcc main.c -ldl -o main&&
./main

Starting to look neater and neater. Thanks @tgingold.

Edit

I'll just reference #640 to link this comment to that issue.

umarcor commented 4 years ago

@RocketRoss, I think that the first version of https://umarcor.github.io/ghdl-cosim/index.html is almost ready. Would you mind having a look?

Example shared/shghdl is what we've been talking about in this issue. This is the log of the execution: https://github.com/umarcor/ghdl-cosim/runs/578738118?check_suite_focus=true#step:4:11.

I used ghdl -e -Wl,-Wl,--version-script=../../vhpidirect.ver -o tb.so tb only for now. However, when the initial version is upstreamed, I'd like to work on three PRs:

radonnachie commented 4 years ago

@umarcor I'm reading through it. I'll rebuild the older --version-script enabled version and double check that example my side :)

anything else in particular you'd like me to check?

umarcor commented 4 years ago

@umarcor I'm reading through it. I'll rebuild the older --version-script enabled version and double check that example my side :)

Good!

anything else in particular you'd like me to check?

Just a quick readthrough to ensure that there is nothing clearly badly formatted or which should not be there. Note that all the content except the examples is basically copied from the current Foreign.rst, split and extended. Hence, most of the content should already be familiar. Cross-references to sections in the main docs should work transparently.

Examples 'Demo' and 'Access to array' are placeholders only. Not to be published at first.

radonnachie commented 4 years ago

Yup cross references are lining up, and I like the split. Reads nicely.

Do you mind if I nitpick over little things (not grammar, just extra explicit sentences/hints)? I'm reading it as if I were as naive as I was when I first started?

ensure that there is nothing clearly badly formatted

I can also save the little changes for later (I'll note them). Your preference?

umarcor commented 4 years ago

Sure. I'll be disconnected for some hours now and, otherwise, I have other tasks I can do. Hence, you can open a PR with those little details and changes and I'll avoid doing text modifications meanwhile.

Note that I added many comments to places in the main docs such as https://ghdl.readthedocs.io/en/latest/using/CommandReference.html#list-link-list-link or https://ghdl.readthedocs.io/en/latest/using/Simulation.html#cmdoption-ghdl-ggeneric. Also, for each section in the cosim docs, info is split between the section and the examples that correspond to that section (e.g. "Wrapping a simulation (ghdl_main)" and "Examples/Wrapping").

Instead of writing changes straighaway, better note them and ensure that they are not already written somewhere else. If in doubt, I can tell you. Of course, suggestions to move content are also welcome.

umarcor commented 4 years ago

@RocketRoss, since ghdl/ghdl-cosim is ready now, let's talk about tests regarding -Wl,-Wl,-u,ghdl_main, -shared and -Wl,-Wl,--version-script= in ghdl/ghdl-cosim#2. We will keep this issue open for supporting restart in GRT. Does it sound good to you?