Help with mixing C and C++ code


Topic author
mberryman
Active Contributor
Posts: 27
Joined: Sat Sep 02, 2023 1:31 pm
Reputation: 0
Location: Colorado Springs, CO, USA
Status: Offline

Help with mixing C and C++ code

Post by mberryman » Tue Nov 07, 2023 2:42 am

Ok, I'm stumped. What is the syntax that would allow a C++ routine to call a C routine that is using 32-bit pointers? The following illustrates the issue I am trying to resolve:

Code: Select all

$ type test.cxx
extern "C" {
extern int load_defaults(const char *conf_file, const char **groups,
                       int *argc, __char32_t ***argv);
}

static const char *load_default_groups[]=
{ "mysqladmin", "client", "client-server", "client-mariadb", 0 };

int main(int argc,char *argv[])
{

        int x = load_defaults("my",load_default_groups,&argc,&argv);

}
$ cxx test
test.cxx;1:12:10: error: no matching function for call to 'load_defaults'
        int x = load_defaults("my",load_default_groups,&argc,&argv);
                ^~~~~~~~~~~~~
test.cxx;1:2:12: note: candidate function not viable: no known conversion from 'char * __ptr32 **' to 'char32_t ***' for 4th argument
extern int load_defaults(const char *conf_file, const char **groups,
           ^
1 error generated.
$
Also, what is the magic incantation that would grant a C++ routine access to fmod and exp2?

Code: Select all

$ cxx/version
clang version 10.0.1 (git@bitbucket.org:vms_software/llvm-10.0.1.git b2ed69f05fb4239b21b6ff2f806caaf4691c9719)
Build date: 09-19-2023
Target: x86_64-OpenVMS
Thread model: posix
InstalledDir: $1$DGA3:[SYS0.SYSCOMMON.][SYSEXE]


joukj
Master
Posts: 175
Joined: Thu Aug 27, 2020 5:50 am
Reputation: 0
Status: Offline

Re: Help with mixing C and C++ code

Post by joukj » Tue Nov 07, 2023 4:56 am

I wonder if you can make this example to work. The problem is that argv (in main) is in 64-bit space. Passing that to a 32-bit C-routine will cause loss of data and probalby a crash.

In my own projects I noticed that it is very hard to combine C end CXX with 2 completely different compilers. I ended up by compiling everything with C++. However there should also be a possibility to use Clang as a C-compiler, but I do not have (yet) any experience with that.

if you change the argument of the function call
from
&argv
to
(__char32_t***) &argv
you get only a warning. Testing if the code works as expected is than essential.

Probably you get also problems with the othjer arguments, beeing 64 bit variables.
Last edited by joukj on Tue Nov 07, 2023 5:19 am, edited 2 times in total.


pustovetov
VSI Expert
Contributor
Posts: 18
Joined: Thu Sep 14, 2023 1:26 am
Reputation: 0
Status: Offline

Re: Help with mixing C and C++ code

Post by pustovetov » Tue Nov 07, 2023 5:09 am

mberryman wrote:
Tue Nov 07, 2023 2:42 am
Ok, I'm stumped. What is the syntax that would allow a C++ routine to call a C routine that is using 32-bit pointers? The following illustrates the issue I am trying to resolve:
Try something like this:

Code: Select all

$ type test.cxx
#pragma __required_pointer_size __save
#pragma __required_pointer_size 32
extern "C" {
extern int load_defaults(const char *conf_file, const char **groups,
                       int *argc, char * __char_ptr_ptr32 argv);
}
#pragma __required_pointer_size __restore
Last edited by pustovetov on Tue Nov 07, 2023 5:22 am, edited 1 time in total.


Topic author
mberryman
Active Contributor
Posts: 27
Joined: Sat Sep 02, 2023 1:31 pm
Reputation: 0
Location: Colorado Springs, CO, USA
Status: Offline

Re: Help with mixing C and C++ code

Post by mberryman » Tue Nov 07, 2023 10:54 am

I have tried casting. While it does result in a warning instead of an error, the program crashes on execution.

I have also tried changing the pointer size. That results in this warning:
no known conversion from 'char * __ptr32 **' to 'char32_t * __ptr32 * __ptr32 * __ptr32' for 4th argument


jhamby
Contributor
Posts: 22
Joined: Wed Oct 04, 2023 8:59 pm
Reputation: 0
Status: Offline

Re: Help with mixing C and C++ code

Post by jhamby » Tue Nov 07, 2023 5:32 pm

I don't have a solution for you, but I can repro the crash you're seeing, and I believe what you're doing should work, since argc and the argv array are all 32-bit pointers and in 32-bit address space by default in Clang.

If you were to use "/Pointer=64=argv" to compile your C++, things would be different, and in that case you'd have to copy your argv array into a 32-bit pointer array, but I believe the pointer to argc and the pointed-to argv strings should still be in 32-bit space in that case.

I have a similar crashing issue with trying to write Hello, world! in x86 assembly that this thread looks like a good place for me to report. I posted on comp.os.vms about it and got the suggestion to look at the link map to see what's different between my non-working asm code (I even commented everything out but "ret" and it still crashed) and an equivalent program in Pascal. The same technique would probably show some differences between C and C++.

My do-nothing asm app looks like:

Code: Select all

        .global ELF$TFRADR

        .section        $CODE$, "ax", "progbits"  # EXE,SHR
        .align  16

        .cfi_startproc
ELF$TFRADR:
START:
        ret
        .cfi_endproc
I assembled with "llvmmc --filetype=obj -o=vms-hello.obj vms-hello.s" and linked and it gives an ACCVIO, reason mask 14, virtual address 0. Looking at the link map, I see a few differences:

- my ELF$TFRADR has value "80000000-RQ" (Relocatable, Quad value), while the Pascal version has value "80000000-RCQ" (C = code address)
- my $CODE$ section is marked NOSHR, while the Pascal one is marked SHR.
- the Pascal code has a ".data.rel.ro" section that mine doesn't (even the versions with a .data or .rodata section)

I'm assuming that my problem is that I need to use VMS-specific assembler directives to set up my ELF sections. But maybe it's a bug in the VMS version of llvm-mc. Your crash mixing C and C++ code also has me wondering if there are multiple issues with the x86-64 version of the linker and with its handling of ELF metadata.


hb
Valued Contributor
Posts: 79
Joined: Mon May 01, 2023 12:11 pm
Reputation: 0
Status: Offline

Re: Help with mixing C and C++ code

Post by hb » Tue Nov 07, 2023 6:04 pm

jhamby wrote:
Tue Nov 07, 2023 5:32 pm
My do-nothing asm app looks like:
Add a

Code: Select all

       .type ELF$TFRADR, @function
and it will work, ahem, you forgot a return code.


jhamby
Contributor
Posts: 22
Joined: Wed Oct 04, 2023 8:59 pm
Reputation: 0
Status: Offline

Re: Help with mixing C and C++ code

Post by jhamby » Tue Nov 07, 2023 6:14 pm

Wonderful, thanks! I knew it was something small like that. My original code called SYS$EXIT with return status 1, after calling LIB$PUT_OUTPUT, and now that code works as well.


hb
Valued Contributor
Posts: 79
Joined: Mon May 01, 2023 12:11 pm
Reputation: 0
Status: Offline

Re: Help with mixing C and C++ code

Post by hb » Tue Nov 07, 2023 6:53 pm

jhamby wrote:
Tue Nov 07, 2023 6:14 pm
Wonderful, thanks! I knew it was something small like that. My original code called SYS$EXIT with return status 1, after calling LIB$PUT_OUTPUT, and now that code works as well.
Ah, yes, the SYS$EXIT lets you get away with a missing push %rbp or why did your source (on c.o.v) have a pop %rbp before the ret? You don't need to call SYS$EXIT, you can set %rax to 1 before the ret - or leave in %rax what LIB$PUT_OUTPUT put there. And on VMS you should always establish a frame pointer. And the stack should be aligned to a 16 byte boundary, before making a call. All this requires a few more .cfi directives to make it work well.


jhamby
Contributor
Posts: 22
Joined: Wed Oct 04, 2023 8:59 pm
Reputation: 0
Status: Offline

Re: Help with mixing C and C++ code

Post by jhamby » Wed Nov 08, 2023 3:26 pm

There wasn't a good reason for the bugs in my code, or for explicitly calling SYS$EXIT instead of returning the status. I was copying-and-pasting from disassembly of other files and trying a bunch of unnecessary experiments.

The stray "pop %rbp" came from the Pascal version that pushed some variables on the stack and set up the string descriptor on the stack, pointing to the string itself in the data segment. I knew about the 16-byte stack alignment rule and realized that if I didn't touch the stack at all, it should be aligned when I enter. So I deleted the pushes and pops, minus the one I missed.

Added in 3 minutes 20 seconds:
I'm more curious now about the original topic of the thread, crashes mixing C and C++. My problem was unrelated. The C/C++ boundary is really confusing now with the different default pointer sizes, the different size_t size in 64-bit pointer mode, the different defaults for uppercase vs. as-is names, and many other details.


hb
Valued Contributor
Posts: 79
Joined: Mon May 01, 2023 12:11 pm
Reputation: 0
Status: Offline

Re: Help with mixing C and C++ code

Post by hb » Wed Nov 08, 2023 4:43 pm

jhamby wrote:
Wed Nov 08, 2023 3:29 pm
The stray "pop %rbp" came from the Pascal version that pushed some variables on the stack and set up the string descriptor on the stack, pointing to the string itself in the data segment. I knew about the 16-byte stack alignment rule and realized that if I didn't touch the stack at all, it should be aligned when I enter. So I deleted the pushes and pops, minus the one I missed.
Please read the VMS Calling standard. Or replace LIB$PUT_OUTPUT with DECC$TXPRINTF, push the address of an .asciz "message" instead of the descriptor on the stack before calling it and see what happens.
.

Post Reply