libstdc++ as bytecode, and compiling C++ to C

I've compiled all the object files that make up libstdc++ and libsupc++
into LLVM bytecode:
  http://goanna.cs.rmit.edu.au/~emil/libstdcxx.tar.bz2 (438KB)

A simple test program, x.cpp:

  #include <iostream>
  int main() { std::cout << "hello world\n"; return 0; }

$ llvm-g++ -emit-llvm -c x.cpp
$ llvmc -o=out x.o std/*.o sup/*.o
$ lli out.bc
Segmentation fault (core dumped)
$

Oops, no go. Try a different way:

$ llvm-g++ -emit-llvm -c x.cpp
$ llvm-link -o=linked.o x.o std/*.o sup/*.o
$ lli linked.o
hello world
$

So far, so good! Compile to C:

$ llc -o=cbe.c -march=c linked.o
WARNING: this target does not support the llvm.stacksave intrinsic.
$ gcc cbe.c
/var/tmp//ccVAM4W2.o(.text+0x329a): In function `operator new(unsigned int)':
: undefined reference to `__cxa_throw'
[...and more errors]
$

But __cxa_throw is right there, in sup/eh_throw.o, and in linked.o, it
just isn't being emitted as C code. (at this point, I suspect the
problem might be that I don't quite understand how some of the llvm
tools are intended to work - e.g. llvm-link vs llvmc)

Strangely enough:

$ llvm-g++ -emit-llvm -c x.cpp
$ llvm-link -o=linked.o x.o std/*.o sup/*.o
$ llvmc -o=out linked.o
$ llc -o=cbe.c -march=c out.bc
WARNING: this target does not support the llvm.stacksave intrinsic.
$ gcc cbe.c
$ ./a.out
hello world
$

Works!

--Emil

Emil:

Thanks for your email. I tried the above and got the following errors:

$ llvm-link -o=linked.o x.o std/*.o sup/*.o
llvm-link: error loading file 'std/allocator-inst.o'

And when I do this:
$ llvmc -o=out x.o std/*.o sup/*.o
llvm-ld: error: Cannot load file 'std/allocator-inst.o'Bytecode file
'std/allocator-inst.o' could not be loaded: Unknown bytecode version
number: 6 (Vers=6, Pos=13)
llvmc: Action failed

I'm using LLVM 1.8. Is it due to compatibility problem?

Thanks.

Napi

I've compiled all the object files that make up libstdc++ and libsupc++
into LLVM bytecode:
  http://goanna.cs.rmit.edu.au/~emil/libstdcxx.tar.bz2 (438KB)

A simple test program, x.cpp:

  #include <iostream>
  int main() { std::cout << "hello world\n"; return 0; }

$ llvm-g++ -emit-llvm -c x.cpp
$ llvmc -o=out x.o std/*.o sup/*.o
$ lli out.bc
Segmentation fault (core dumped)
$

llvmc isn't a completed tool. In particular it doesn't handle native
linking properly. However, I'm not sure what it would do in your example
above that would cause the program to seg fault. Can you get a stack
trace?

Oops, no go. Try a different way:

$ llvm-g++ -emit-llvm -c x.cpp
$ llvm-link -o=linked.o x.o std/*.o sup/*.o
$ lli linked.o
hello world
$

So far, so good! Compile to C:

llvm-link should work fine because its just dealing with bytecode. BTW,
You could put all the std/*.o and sup/*.o files into a bc archive using
llvm-ar and then just link with that archive.

$ llc -o=cbe.c -march=c linked.o
WARNING: this target does not support the llvm.stacksave intrinsic.
$ gcc cbe.c
/var/tmp//ccVAM4W2.o(.text+0x329a): In function `operator new(unsigned int)':
: undefined reference to `__cxa_throw'
[...and more errors]
$

But __cxa_throw is right there, in sup/eh_throw.o, and in linked.o, it
just isn't being emitted as C code. (at this point, I suspect the
problem might be that I don't quite understand how some of the llvm
tools are intended to work - e.g. llvm-link vs llvmc)

CBE doesn't support exceptions ?

Strangely enough:

$ llvm-g++ -emit-llvm -c x.cpp
$ llvm-link -o=linked.o x.o std/*.o sup/*.o
$ llvmc -o=out linked.o
$ llc -o=cbe.c -march=c out.bc
WARNING: this target does not support the llvm.stacksave intrinsic.

CBE doesn't support llvm.stacksave

$ gcc cbe.c
$ ./a.out
hello world
$

Works!

However it doesn't seem to matter for this program.

> I've compiled all the object files that make up libstdc++ and libsupc++
> into LLVM bytecode:
> http://goanna.cs.rmit.edu.au/~emil/libstdcxx.tar.bz2 (438KB)
>
> A simple test program, x.cpp:
>
> #include <iostream>
> int main() { std::cout << "hello world\n"; return 0; }
>
> $ llvm-g++ -emit-llvm -c x.cpp
> $ llvmc -o=out x.o std/*.o sup/*.o
> $ lli out.bc
> Segmentation fault (core dumped)
> $
>
> Oops, no go. Try a different way:
>
> $ llvm-g++ -emit-llvm -c x.cpp
> $ llvm-link -o=linked.o x.o std/*.o sup/*.o
> $ lli linked.o
> hello world

Emil:

Thanks for your email. I tried the above and got the following errors:

$ llvm-link -o=linked.o x.o std/*.o sup/*.o
llvm-link: error loading file 'std/allocator-inst.o'

And when I do this:
$ llvmc -o=out x.o std/*.o sup/*.o
llvm-ld: error: Cannot load file 'std/allocator-inst.o'Bytecode file
'std/allocator-inst.o' could not be loaded: Unknown bytecode version
number: 6 (Vers=6, Pos=13)
llvmc: Action failed

I'm using LLVM 1.8. Is it due to compatibility problem?

Yes. version 6 is the LLVM 1.9 bytecode format and 1.8 doesn't know up
to downgrade it.

> I've compiled all the object files that make up libstdc++ and libsupc++
> into LLVM bytecode:
> http://goanna.cs.rmit.edu.au/~emil/libstdcxx.tar.bz2 (438KB)
>
> A simple test program, x.cpp:
>
> #include <iostream>
> int main() { std::cout << "hello world\n"; return 0; }
>
> $ llvm-g++ -emit-llvm -c x.cpp
> $ llvmc -o=out x.o std/*.o sup/*.o
> $ lli out.bc
> Segmentation fault (core dumped)
> $

llvmc isn't a completed tool. In particular it doesn't handle native
linking properly. However, I'm not sure what it would do in your example
above that would cause the program to seg fault. Can you get a stack
trace?

Actually, it looks to me like it generates bad code.

$ llvm-dis < out.bc | grep -- -3
  %tmp4.i.i = getelementptr int (...)** %tmp.i.i, int -3
[and a bunch more, one of which is in main()...]

$ llc -march=c -o=cbe.c out.bc
WARNING: this target does not support the llvm.stacksave intrinsic.
$ gcc -g cbe.c
[n.b.: compiles successfully!]
$ gdb a.out
(gdb) run
Starting program: a.out

Program received signal SIGSEGV, Segmentation fault.
0x08048958 in main () at cbe.c:1154
1154 ltmp_173_15 = *((int *)(&ltmp_172_54[-3]));
(gdb) print ltmp_172_54
$1 = (int (**)()) 0x0

Can I send you bytecode files or any further diagnostics to chase this
up?

> Oops, no go. Try a different way:
>
> $ llvm-g++ -emit-llvm -c x.cpp
> $ llvm-link -o=linked.o x.o std/*.o sup/*.o
> $ lli linked.o
> hello world
> $
>
> So far, so good! Compile to C:

llvm-link should work fine because its just dealing with bytecode. BTW,
You could put all the std/*.o and sup/*.o files into a bc archive using
llvm-ar and then just link with that archive.

I thought so, and I even tried playing with llvm-ar, but couldn't figure
it out.

$ llvm-ar rs mylib.a std/*.o sup/*.o
llvm-ar: creating mylib.a
$ llvm-link -o=linked.o x.o mylib.a
llvm-link: error loading file 'mylib.a'

> $ llc -o=cbe.c -march=c linked.o
> WARNING: this target does not support the llvm.stacksave intrinsic.
> $ gcc cbe.c
> /var/tmp//ccVAM4W2.o(.text+0x329a): In function `operator new(unsigned int)':
> : undefined reference to `__cxa_throw'
> [...and more errors]
> $
>
> But __cxa_throw is right there, in sup/eh_throw.o, and in linked.o, it
> just isn't being emitted as C code. (at this point, I suspect the
> problem might be that I don't quite understand how some of the llvm
> tools are intended to work - e.g. llvm-link vs llvmc)

CBE doesn't support exceptions ?

Fair enough. It's just that if I use llc to compile sup/eh_throw.o to a
C file, it contains a __cxa_throw() function. (whether it does the
right thing or not, I don't know - I haven't gotten that far)

But, after the big llvm-link step, cbe.c doesn't contain a __cxa_throw()
function even though it's called from the code.

> Strangely enough:
>
> $ llvm-g++ -emit-llvm -c x.cpp
> $ llvm-link -o=linked.o x.o std/*.o sup/*.o
> $ llvmc -o=out linked.o
> $ llc -o=cbe.c -march=c out.bc
> WARNING: this target does not support the llvm.stacksave intrinsic.

CBE doesn't support llvm.stacksave

Fair enough. =)

> $ gcc cbe.c
> $ ./a.out
> hello world
> $
>
> Works!

However it doesn't seem to matter for this program.

The program is very simple, and doesn't use any EH itself, but I think
pieces of libstdc++ do...

--Emil

>
> llvmc isn't a completed tool. In particular it doesn't handle native
> linking properly. However, I'm not sure what it would do in your example
> above that would cause the program to seg fault. Can you get a stack
> trace?

Actually, it looks to me like it generates bad code.

Well, like I said, it isn't complete.

$ llvm-dis < out.bc | grep -- -3
  %tmp4.i.i = getelementptr int (...)** %tmp.i.i, int -3
[and a bunch more, one of which is in main()...]

I don't see what's so bad about this ?

$ llc -march=c -o=cbe.c out.bc
WARNING: this target does not support the llvm.stacksave intrinsic.
$ gcc -g cbe.c
[n.b.: compiles successfully!]
$ gdb a.out
(gdb) run
Starting program: a.out

Program received signal SIGSEGV, Segmentation fault.
0x08048958 in main () at cbe.c:1154
1154 ltmp_173_15 = *((int *)(&ltmp_172_54[-3]));
(gdb) print ltmp_172_54
$1 = (int (**)()) 0x0

Yeah, I was asking for a stack trace in the program generated by llvmc.
The CBE isn't going to help much here, at least not without the cbe
source.

Can I send you bytecode files or any further diagnostics to chase this
up?

Sure.

> > Oops, no go. Try a different way:
> >
> > $ llvm-g++ -emit-llvm -c x.cpp
> > $ llvm-link -o=linked.o x.o std/*.o sup/*.o
> > $ lli linked.o
> > hello world
> > $
> >
> > So far, so good! Compile to C:
>
> llvm-link should work fine because its just dealing with bytecode. BTW,
> You could put all the std/*.o and sup/*.o files into a bc archive using
> llvm-ar and then just link with that archive.

I thought so, and I even tried playing with llvm-ar, but couldn't figure
it out.

$ llvm-ar rs mylib.a std/*.o sup/*.o
llvm-ar: creating mylib.a

That's correct.

$ llvm-link -o=linked.o x.o mylib.a
llvm-link: error loading file 'mylib.a'

llvm-link only understands bytecode files. It can't read archives. Try
llvm-ld or gccld instead. If gccld, use the -link-as-library option.

> > $ llc -o=cbe.c -march=c linked.o
> > WARNING: this target does not support the llvm.stacksave intrinsic.
> > $ gcc cbe.c
> > /var/tmp//ccVAM4W2.o(.text+0x329a): In function `operator new(unsigned int)':
> > : undefined reference to `__cxa_throw'
> > [...and more errors]
> > $
> >
> > But __cxa_throw is right there, in sup/eh_throw.o, and in linked.o, it
> > just isn't being emitted as C code. (at this point, I suspect the
> > problem might be that I don't quite understand how some of the llvm
> > tools are intended to work - e.g. llvm-link vs llvmc)
>
> CBE doesn't support exceptions ?

Fair enough. It's just that if I use llc to compile sup/eh_throw.o to a
C file, it contains a __cxa_throw() function. (whether it does the
right thing or not, I don't know - I haven't gotten that far)

Probably not. Again, the CBE doesn't support exceptions and it would
have to understand that __cxa_throw is part of the exception handling.

But, after the big llvm-link step, cbe.c doesn't contain a __cxa_throw()
function even though it's called from the code.

I'm not surprised.

> > Strangely enough:
> >
> > $ llvm-g++ -emit-llvm -c x.cpp
> > $ llvm-link -o=linked.o x.o std/*.o sup/*.o
> > $ llvmc -o=out linked.o
> > $ llc -o=cbe.c -march=c out.bc
> > WARNING: this target does not support the llvm.stacksave intrinsic.
>
> CBE doesn't support llvm.stacksave

Fair enough. =)

> > $ gcc cbe.c
> > $ ./a.out
> > hello world
> > $
> >
> > Works!
>
> However it doesn't seem to matter for this program.

The program is very simple, and doesn't use any EH itself, but I think
pieces of libstdc++ do...

Okay.