For example, say you want to pass a 16-byte struct as an argument: how do you do it? Do you store the struct in memory and pass an int32 pointer to its start address? Or an int64 pointer? Maybe you encode it as two int64s? Once you've made a choice, good luck calling functions generated by a compiler that made a different one!
Another problem (in the web context) is blocking--Emscripten runs into this one. You can't suspend WebAssembly execution in the middle of calling out to an imported function. If a WebAssembly program wants to read keypresses interactively, it can't use a blocking function like read(). You have to pass the keypresses in at the outer level--or reimplement the call stack yourself like Go did (https://docs.google.com/document/d/131vjr4DH6JFnb-blm_uRdaC0...).
In general, WebAssembly code today is very tied to the JavaScript code that manages its interaction with the outside world. You can't just write a WebAssembly program that uses OpenGL. You also need to write the JavaScript that turns those calls into WebGL calls. I don't think this is a fundamental problem--we just haven't seen standards develop yet. As platforms start to define their API directly in terms of WebAssembly, without a JavaScript layer, we may see more of a "standard ABI" develop. Until then, it's hard to know what kind of APIs to target or support as an application or compiler writer.