Reputation: 1048
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:
ioperm
is in libc, but outb
is notioperm
and outb
are defined in the same header file <sys/io.h>
outb
in glibc
, however on the system glibc
is defined as libc
/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
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