hexagonal-sun / bic

A C interpreter and API explorer.
GNU General Public License v2.0
815 stars 36 forks source link

Allow absolute path for library files. #16

Open cjwelborn opened 5 years ago

cjwelborn commented 5 years ago

I noticed that any library file I use has to be located in the system/global directory. Things like -l ./libforme.so are not allowed. -l forme is not allowed either if the file is in the current directory. It would be nice to at least allow an absolute path to the libraries that are loaded.

I'm having other issues with libraries. I'll probably post another report for those.

hexagonal-sun commented 5 years ago

Hmm, seems to work for me:

 $ cat test.c
int foo(int n)
{
    return n * 2;
}
 $ gcc -shared -o foo.so test.c
 $ ./src/bic -l ./foo.so
BIC> int foo(int n);

BIC> foo(20);
40
BIC>
cjwelborn commented 5 years ago

@hexagonal-sun, when I try the example you provided it works fine. When I try it on one of my own shared libs it doesn't:

Example Screenshot

The file is there, but for some reason it wants to search for it as if I typed 'colr'.

cjwelborn commented 5 years ago

Which, by the way, bic -l colr doesn't work either, even though there is a file called libcolr.so in the current directory. I haven't looked at bic's code because I've been a little busy lately, but maybe I can help with this. I'll see what I can do.

cjwelborn commented 5 years ago

bic -l colr does work if I copy/symlink the file into /usr/lib, but it won't work in ~/.local/lib.

hexagonal-sun commented 5 years ago

Very strange. Looking at the code it first attempts to open the file as written on the command line here and I would have expected this to work. If you could maybe debug this on your end that would be great.

bic -l colr does work if I copy/symlink the file into /usr/lib, but it won't work in ~/.local/lib.

bic doesn't look for libraries in ~/.local/lib. Is that somewhere that it should maybe look?

Ideally I need to find out how the system does proper library resolution and follow that. It seems as though dlopen doesn't cover all bases.

cjwelborn commented 5 years ago

I'll take a look and get back to you. If I could load a local library file bic would be awesome for debugging. I'll check it out when I get home.

cjwelborn commented 5 years ago

@hexagonal-sun, I figured out what the problem is, and it's related to issue #17. I don't have a fix for it right now, but let me tell you what I've found.

The library I am testing with, libcolr.so, is one of mine. It happens to depend on libm (which is a linker script pointing to /lib/x86_64-linux-gnu/libm.so.6 on my machine. The reason the first call to dlopen fails in open_library() is because it tries to pull-in the libm dependency and that fails like issue #17.

I made a little program that calls open_library() like bic does, except it just prints whether the call succeeded or not. I can make all of this work by manually specifying the dependencies, in order, on the command line. This works for my test program, and in bic:

bic -l /lib/x86_64-linux-gnu/libm.so.6 -l ./libcolr.so

It's a workaround. I wish bic could use the linker script, because then -l ./libcolr.so would be the only thing needed (i think). I know how much work that would be though. I haven't used dlopen very much. I may look into how it grabs the dependency libraries. The man page has only this to say:

If the object specified by filename has dependencies on other shared objects, then these are also automatically loaded by the dynamic linker using the same rules. (This process may occur recursively, if those objects in turn have dependencies, and so on.)

This issue, and #17, led me to a couple other features that would be really useful to me, and if I'm able to, I will try to help and make a pull request:

These two things probably need a new issue, but I've already made two in one day and I don't want to flood you with feature requests (especially with no pull-requests to go with them). The thing is, I have been looking for something like bic for a long time. I have cling (REPL for C++), and I've written my own little C-snippet compiler that just compiles arbitrary C code/files with decent defaults, but it's not a REPL. So I really appreciate you putting this out there. I'd like to hear what you think about the two bullet-points above, even if it's just "never gonna happen" or "make a PR or go home".

TLDR: Issue could probably be renamed: -l fails on dependency lib if it's a linker script.

cjwelborn commented 5 years ago

Oh yeh, and I was wrong about the ~/.local/lib thing anyway. dlopen knows where to find libraries because of ldconfig (/etc/ld.so.conf), and if you wanted to load a library from anywhere else all you would need to do is provide the absolute path to it. I don't think bic has to mess with custom library paths like -L for gcc/clang.

cjwelborn commented 5 years ago

I just found this, which could possibly help bic deal with GNU linker scripts. If you knew that libm was requested, you could get the absolute file path from <gnu/lib-names.h>. Something like:

#include <dlfcn.h>
#include <gnu/lib-names.h>

int open_library(char* libname) {
    if (strcmp(libname, "m") == 0) {
        if (dlopen(LIBM_SO, RTLD_NOW | RTLD_GLOBAL)) {
            printf("Loaded libm from lib-names.h: %s\n", LIBM_SO);
            return 1;
        }
    }
    // ...fallback to normal behavior.
    return 0;
}

The gnu/lib-names.h on my machine pulls in the definitions based on architecture, but it's format looks exactly like this (just macro definitions for file paths that dlopen can find).

It turns out that the linker-script stuff is specific to the linker program, not dlopen. Long story short, a parser for the scripts would probably need to be written which is a whole other can of worms to open.

hexagonal-sun commented 5 years ago

Many thanks for looking at this. I would have thought that dlopen() would be smart enough to know where to find libm and open it for you. I've just tried on my machine and it appears to work (I'm running Arch Linux):

 $ cat test.c
#include <math.h>
double mysin(double d)
{
    return sin(d);
}
 $ gcc -lm -shared -o foo.so test.c
 $ ./src/bic -l ./foo.so 
BIC> double mysin(double d);

BIC> mysin(0.5);
0.479426

So not too sure exactly what is going on.

If you knew that libm was requested, you could get the absolute file path from <gnu/lib-names.h>

I really like this idea and it's a proper fix for #17. I'll cobble something together and push it today. I'm not too sure if this will help opening libcolr.so though as dlopen() doesn't call back into bic's code to query where to find libm.

In regards to the other points you've raised, please feel free to raise issues for them. I think they're great ideas and the ability for bic to parse multiple source files without calling main() was something that was on my radar anyway. I never thought about using bic as a scripting engine with a #!/usr/bin/env bic before that would be really cool! Anyway if you could raise the issues we can talk about them in more depth there and flesh out how this will all work.

Thanks!