Portable I/O

I’m attempting to use file I/O across platforms from LLVM assembly using the standard GNU C library: fprintf(), stdin/stdout, etc. Ideally I’d like to simply provide a single bitcode file that could be compiled on each platform, but because the internals of the I/O on each platform is different, this is not currently workable.

So my question is this: How do you suggest doing I/O in a portable way from LLVM assembly?

My current thoughts run along two lines:

  1. Writing a non-portable wrapper around the I/O routines to present a common interface to the calling module.

  2. Conditional assembly for each platform, but I don’t see any facilities for this in LLVM assembly.

Are there any other ways to do this or any projects in the works that may provide a solution?

Thanks,
Mike

"Michael Ness" <mike@liquido2.com> writes:

I'm attempting to use file I/O across platforms from LLVM assembly
using the standard GNU C library: fprintf(), stdin/stdout, etc.
Ideally I'd like to simply provide a single bitcode file that could be
compiled on each platform, but because the internals of the I/O on
each platform is different, this is not currently workable.

Why not library calls?

[snip]

Hello Óscar,

The problem with that idea is that they require a pointer to a FILE structure. This file structure is included from stdio.h which has macros and conditional compilation all over the place. There are no constructors in these libraries to call and, as such, they are platform dependent. Is there any way to link in an external type definition to an opaque type? We'd need to include some equivalent of stdio.h into the bitcode.

Thanks for trying,

--Sam

I think that the point is that you can define your own standard runtime interfaces:

void *myopen(const char*path) {
  return fopen(path, ...);
}

That way you're not exposed to libc differences, you have a standard interface that you define.

-Chris

Maybe my experience hand-coding LLVM will actually be of some help. What I did for this case is what I think Chris is suggesting--I have a .c file with functions that return whatever FILE* I need as a void* (I think--could have been a char), and a .ll file that declares the function as returning an i8*.

Perhaps there is a more sophisticated way, but that seems to work just fine. Basically anything that is not guaranteed to be a symbol the linker can see gets a wrapper function written in C. I think I also did this for some of libc's many types (ptrdiff_t and size_t, for example) that I shouldn't technically assume anything about. I didn't *need* portability, but I tried to work in that direction anyway.

I have some other tricks, but they depend on the fact that I actually run LLVM code through CPP, which I assume most people have too much good taste to do.

7x57

Thanks everyone, a set of wrapper routines it will be then.

Dustin, are the routines you wrote open source or do you know if there is already a project that provides such a portable interface to libc for LLVM? If not, I'll write my own routines, but if there is a way to adopt a common standard or avoid reinventing the wheel I'm all for it.

Mike

I know of no project for this sort of thing--I just solved my own problems as I went, and only did what I needed (or what I thought I needed at the time) for my experiment. I put it under the GPL3 just so I didn't release code in the wild with ambiguous terms, so you're entitled to use it without my permission; the public GIT repo is on github:

and while documentation wasn't a big priority the README should at least tell you which files are what. You want to look at system_c.c for the little C wrapper functions and system.llh for the llvm declarations--keep in mind that I'm using CPP though. c_defs.c is how I import type definitions and the like--it writes an llvm header with the correct LLVM definitions for whatever the local machine uses for stuff like size_t, ptrdiff_t, and the like.

If you want to know what sort of mad project it is, the developer's blog is at

I hope to get back to it and put in the last bits to make it Turing complete next week (basically it needs user-defined symbols and lambda expressions).

Feel free to contact me about it if it isn't making sense or you want to know why I did some crazy thing.

Dustin