The Brofessor
The Brofessor

Reputation: 1048

Julia ccall outb - Problems with libc

I run the following ccall's:

status = ccall((:ioperm, "libc"), Int32, (Uint, Uint, Int32), 0x378, 5, 1)
ccall((:outb, "libc"), Void, (Uint8, Uint16), 0x00, 0x378)

After the second ccall I receive the following Error message:

ERROR: ccall: could not find function outb in library libc
 in anonymous at no file
 in include at ./boot.jl:245
 in include_from_node1 at loading.jl:128
 in process_options at ./client.jl:285

After some research and messing around I found the following information:

  1. ioperm is in libc, but outb is not
  2. However, both ioperm and outb are defined in the same header file <sys/io.h>
  3. An equivalent version of C code compiles and runs smoothly.
  4. outb in glibc, however on the system glibc is defined as libc
  5. Same problem with full path names /lib/x86_64-linux-gnu/libc.so.6

EDIT:

Thanks for the insight @Employed Russian! I did not look closely enough to realize the extern declaration. Now, all of my above notes make total sense!

Great, we found that ioperm is a libc function that is declared in <sys/io.h>, and that outb is not in libc, but is defined in <sys/io.h> as a volatile assembly instruction.

Which library, or file path should I use?

Implementation of ccall.

Upvotes: 0

Views: 328

Answers (1)

Employed Russian
Employed Russian

Reputation: 213375

However, both ioperm and outb are defined in the same header file <sys/io.h>

By "defined" you actually mean "declared". They are different. On my system:

extern int ioperm (unsigned long int __from, unsigned long int __num,
                   int __turn_on) __attribute__ ((__nothrow__ , __leaf__));

static __inline void
outb (unsigned char __value, unsigned short int __port)
{
  __asm__ __volatile__ ("outb %b0,%w1": :"a" (__value), "Nd" (__port));
}

It should now be obvious why you can call ioperm but not outb.

Update 1

I am still lost as to how to correct the error.

You can't import outb from libc. You would have to provide your own native library, e.g.

void my_outb(unsigned char value, unsigned short port) {
  outb(value, port);
}

and import my_outb from it. For symmetry, you should probably implement my_ioperm the same way, so you are importing both functions from the same native library.

Update 2

Making a library worked, but in terms of performance it is horrible.

I guess that's why the original is implemented as an inline function: you are only executing a single outb instruction, so the overhead of a function call is significant.

Unoptimized python does x5 better.

Probably by having that same outb instruction inlined into it.

Do you know if outb exist in some other library, not in libc

That is not going to help: you will still have a function call overhead. I am guessing that when you call the imported function from Julia, you probably execute a dlopen and dlsym call, which would impose an overhead of additional several 100s of instructions.

There is probably a way to "bind" the function dynamically once, and then use it repeatedly to make the call (thus avoiding repeated dlopen and dlsym). That should help.

Upvotes: 2

Related Questions