The following short c example uses the standard c library and therefore requires the wasi sdk:
#include <stdio.h>
int main(void)
{
puts("Hello");
return 0;
}
When compiling the code directly with clang to wasm it works without problem:
clang --target=wasm32-unknown-wasi -s -o example.wasm example.c
My understanding of the LLVM tool chain is that I could achieve the same result with either
clang -> LLVM IR (.ll) -> LLVM native object files (.o) -> convert to wasm
clang -> LLVM native object files (.o) -> convert to wasm
I am able to use the second approach with a simple C program which does not use standard lib calls, when trying with the example above I receive a undefined symbol error:
clang --target=wasm32-unknown-wasi -c example.c
wasm-ld example.o -o example.wasm --no-entry --export-all
wasm-ld: error: example.o: undefined symbol: puts
I do not know if my problem is that I use the wrong clang parameters and therefore not export enough information or that the error is in the wasm-ld command.
Would be happy if someone could give me more insight into tool chain, thanks
Related
I am debugging a C program on arm64 with lldb and in order to implement my own debugging function I wrote a standalone debug helper program, compiled it as a dylib and imported it into lldb by using:
(lldb) target modules add debugHelper.dylib
However when I call the function declared in the dylib, lldb errors:
(lldb) expression debugPrint()
error: Couldn't lookup symbols:
_debugPrint
If I type in a random function name (e.g. foo):
(lldb) expression foo()
error: use of undeclared identifier 'foo'
, which makes me believe importing the dylib is indeed successful, since debugPrint is not an undeclared identifier.
// debugHelper.c
#include <stdio.h>
int debugPrint() {
printf("%s\n", "Debug info printed! \n");
return 0;
}
debugHelper.dylib is compiled with:
$ xcrun --sdk iphoneos cc debugHelper.c -o debugHelper.dylib -dynamiclib -arch arm64 -g
I also verified with nm that debugHelper.dylib does have the _debugPrint symbol:
$ nm debugHelper.dylib
0000000000007f2c T _debugPrint
U _printf
U dyld_stub_binder
Results of (lldb) image list :
[263]... debugHelper.dylib.dSYM/Contents/Resources/DWARF/debugHelper.dylib
target modules add loads the binary (and its dSYM, if there is one) into lldb's pool of binaries it knows about. But the dylib has not been loaded into your inferior process -- you will not be able to run the functions in there.
Instead, run dlopen() in your process:
(lldb) p (int)dlopen("debugHelper.dylib", 10)
(that 10 is RTLD_GLOBAL|RTLD_NOW, v. dlfcn.h). There's also an SB API method to do this, SBProcess::LoadImage which doesn't require you to look up the details of dlopen. e.g.
(lldb) script lldb.process.LoadImage(lldb.SBFileSpec("debugHelper.dylib", False), lldb.SBError())
I am trying to compile two *.c files to LLVM bitcode via clang, link them together using llvm-link, and make a single *.wasm file out of it. I built LLVM on my machine via the Makefile provided by https://github.com/yurydelendik/wasmception
This works fine until I use memcpy in the C code. Then llvm-link stops with error:
Intrinsic has incorrect argument type!
void (i8*, i8*, i32, i1)* #llvm.memcpy.p0i8.p0i8.i32
The following is a minimal example to reproduce the issue:
one.c
#define EXPORT __attribute__((visibility("default")))
#include <string.h>
char* some_str();
EXPORT void do_something() {
char* cpy_src = some_str();
char other_str[15];
memcpy(other_str, cpy_src, strlen(cpy_src));
}
two.c
char* some_str() {
return "Hello World";
}
Execute the following commands:
$ clang --target=wasm32-unknown-unknown-wasm --sysroot=../wasmception/sysroot -S -emit-llvm -nostartfiles -fvisibility=hidden one.c -o one.bc
[...]
$ clang --target=wasm32-unknown-unknown-wasm --sysroot=../wasmception/sysroot -S -emit-llvm -nostartfiles -fvisibility=hidden two.c -o two.bc
[...]
Note that no optimization is done because that would eliminate the unnecessary memcpy call here. As I said, this is a minimal example out of context to show the error.
$ llvm-link one.bc two.bc -o res.bc -v
Loading 'one.bc'
Linking in 'one.bc'
Loading 'two.bc'
Linking in 'two.bc'
Intrinsic has incorrect argument type!
void (i8*, i8*, i32, i1)* #llvm.memcpy.p0i8.p0i8.i32
llvm-link: error: linked module is broken!
When I comment out the memcpy call in the example file, the error is gone. Of course this is not an option in the real project I am working at.
Am I doing something wrong? Is it a bad idea in general to use memcpy in a WebAssembly context? Can this be a bug in LLVM/Clang?
Reading through these github issues, it seems the memcpy intrinsic is not currently supported by the WASM backend:
https://github.com/WebAssembly/design/issues/236
https://github.com/WebAssembly/design/issues/1003
As a workaround, you could instruct clang to disable intrinsic expansion using -fno-builtin, so that the generated code will call the actual memcpy function.
I have been using clang-3.5 to happily build bitcode versions of musl libc and
use the result to produce nice stand alone executables.
Recent attempts with clang-3.8 have not been so happy. It seems that
the bitcode clang-3.8 generates uses functions defined in
compiler-rt/lib/builtins
Typical examples of functions I find polluting the bitcode are mulxc3, mulsc3, and muldc3. I can solve this by linking against libgcc, or even the llvm alternative if I had any clear idea of what that was. Though I would rather prevent the problem from happening in the first place.
I have seen mention of flags like rtlib=compiler-rt etc, but have found precious little documentation on the subject.
So here are some simple questions.
Is it possible to prevent clang from using the compiler-rt/lib/builtins
in the emitted bitcode? Or if not
Does llvm produce a version of libgcc that I could use. Actually I would
probably build a bitcode version of it, but that is besides the point.
Love to hear some guidance on this.
Added 12/8/2016: So I will illustrate my issues with a particular workflow that
people can reproduce if they wish, or, more likely, just point out where I am being stupid.
So start by checking out:
musllv
and follow the instructions in the README.to compile (here I am using clang-3.8 on ubuntu 14.04)
WLLVM_CONFIGURE_ONLY=1 CC=wllvm ./configure --target=LLVM --build=LLVM
make
cd lib
extract-bc -b libc.a
you will also need the bitcode of a simple executable. I will use nweb.c here.
wllvm nweb.c -o nweb
extract-bc nweb
Now we can do things like:
clang -static -nostdlib nweb.bc libc.a.bc crt1.o libc.a -o nweb
This workflow goes smoothly for clang-3.5 but for clang-3.8 we get:
clang -static -nostdlib nweb.bc libc.a.bc crt1.o libc.a -o nweb
/tmp/libc-f734a3.o: In function `cpowl':
libc.a.bc:(.text+0xbb9a): undefined reference to `__mulxc3'
/tmp/libc-f734a3.o: In function `cpowf':
libc.a.bc:(.text+0x38f7d): undefined reference to `__mulsc3'
/tmp/libc-f734a3.o: In function `csqrt':
libc.a.bc:(.text+0x78fc3): undefined reference to `__muldc3'
/tmp/libc-f734a3.o: In function `cpow':
libc.a.bc:(.text+0xafafc): undefined reference to `__muldc3'
clang-3.8: error: linker command failed with exit code 1 (use -v to seeinvocation)
So as #paul-brannan points out we could try
clang -static -nostdlib --rtlib=compiler-rt nweb.bc libc.a.bc crt1.o libc.a -o nweb
But this is where I am probably being stupid, because I get:
clang-3.8: warning: argument unused during compilation: '--rtlib=compiler-rt'
irregardless of whether I use it as a linking or compiling flag.
OK so I finally managed to make headway on this. I built llvm-3.8.1 together with the compiler-rt project using wllvm and wllvm++.
One of the build products was libclang_rt.builtins-x86_64.a,
and from this archive I was able to extract the bitcode module
libclang_rt.builtins-x86_64.bc
using the command:
extract-bc -b libclang_rt.builtins-x86_64.a
This bitcode module has definitions for those pesky instrinsics like
__mulxc3, __mulsc3, and __muldc3.
Hallelujah!
Like every new guy am trying to build something with Clang, using the tutorials found here:
Ioarabia Clang Tutorials
I can build the 1st and 2nd tutorial using this command:
export CLANG_LIBS="-lclangTooling -lclangFrontendTool -lclangFrontend -lclangDriver -lclangSerialization -lclangCodeGen -lclangParse -lclangSema -lclangStaticAnalyzerFrontend -lclangStaticAnalyzerCheckers -lclangStaticAnalyzerCore -lclangAnalysis -lclangARCMigrate -lclangRewrite -lclangRewriteFrontend -lclangEdit -lclangAST -lclangLex -lclangBasic -lclang"
and compiling with:
g++ `llvm-config --cxxflags --ldflags ` tool.cpp $CLANG_LIBS `llvm-config --libs --system-libs` -o tool
it works!. When I move onto tutorial 3 using the same command i get the following error:
tutorial3.cpp: In function ‘int main()’: tutorial3.cpp:85:24: error:
invalid initialization of reference of type
‘const clang::PCHContainerReader&’ from expression of type
‘clang::FrontendOptions’
frontendOptions);
^ In file included from tutorial3.cpp:18:0: /usr/local/include/clang/Frontend/Utils.h:66:6: note: in passing argument 3 of ‘void
clang::InitializePreprocessor(clang::Preprocessor&, const
clang::PreprocessorOptions&, const clang::PCHContainerReader&, const
clang::FrontendOptions&)’ void InitializePreprocessor(Preprocessor
&PP, const PreprocessorOptions &PPOpts,
Please can anybody help me? Furthermore are there any know groups of clang users? I tried google groups but didn't found any! Thanks
clang has an option, -x, which can be used to specify the language of subsequent source files passed to it. This caused problems when used like this:
clang -x c++ one.cc a.o b.o c.o
clang will try to interpret the object files a.o, b.o, c.o as source code.
Is there a way to cancel the effect of the -x option so I can pass object files on the same command line?
clang -x c++ one.cc SOMEOPTION a.o b.o c.o
What should SOMEOPTION be to allow clang to interpret the .o files as object files?
I need to use this convoluted command line because I am using a system that calls the compiler automatically to compile some code it generates and there are limits to how much it can be hacked.
could you put the arguments the other way 'round
clang a.o b.o c.o -x c++ one.cc
or compile each file and then link them in a later run
clang -x c++ one.cc -o one.cc.o
clang a.o b.o c.o one.cc.o
This is how in my experience it is actualy used.