5

On linux (for example), we can directly make system calls using the api provided by OS (open/close/read/write) or we can use functions provided by libc (fopen etc) in C.

How is it achieved in other languages?

tan
  • 116
  • 7
  • 1
    See [Wikipedia: Application Programming Interface (API)](http://en.wikipedia.org/wiki/Application_programming_interface#Language_bindings_and_interface_generators) and [Wikipedia: application binary interface (ABI)](http://en.wikipedia.org/wiki/Application_binary_interface) and [Wikipedia: Language binding](http://en.wikipedia.org/wiki/Language_binding) for description of key terms – xmojmr Oct 10 '14 at 11:49

2 Answers2

11

Your initial premises are wrong: on Linux, when you call, say, open(2) in your C code, you're not making the syscall but rather calling the function provided by glibc (or whatever implementation of the C standard library your program happens to be using—there are others, such as μLibc, dietlibc etc), and the implementation of that function actually makes the syscall—properly doing the necessary setup to conform to the target architecture's ABI conventions.

You can make a syscall directly in C but it will look much different from just calling open(); some pointers are this and this.

To recap: the POSIX standard (that one specifying how open(2) and friends should looks like and behave) does only specify a rather high-level interface (in terms of the C programming language) but concrete kernels implementing this standard have their own sets of system calls and conventions on how to call them (which differ between H/W architectures for the same kernel), and it's the C standard library which "knows" how to call out to a concrete kernel which makes sure C programs calling POSIX API end up using appropriate system calls with proper set up. In other words, in a typical C application running on Linux you're not dealing with syscalls directly—you just have an impression you do.

Other languages/runtimes basically have two alternatives:

  • Depend on the target platform's libc and rely on it to mediate between them and the kernel.
  • Directly implement calling the necessary syscalls of the target kernel.

Most of languages/runtimes I'm aware of take the first route (Python, Java to name a few) while some of them take the other route—for instance, the reference implementation of Go, Free Pascal.

Update 2014-10-13 answering the question from @tan's comment:

So, if the first route (libc) is taken, how are libc functions invoked from python/java?

Basically, the approach is similar to that of the syscalls: calling into C is, again, sort-of standardized for each combination of hardware architecture and the C compiler. See this discussion for more info and further pointers.

Note that in reality, most software which is able to interface with C code uses one of these two approaches:

  • It is itself written in C, and hence implementing calling out to dynamically or statically linked in external C code is handled by the compiler which compiled the calling software.

    That is, the only thing your software must be concerned of is properly arranging for its data to be manipulated by the C side. One example is making sure a block of memory passed to the C side won't get garbage-collected until the C side is done with it.

    The cgo subsystem of the Go programming language is one example of this approach.

  • The calling software uses a library (typically written in C to leverage what the C compiler can do for it) which is able to load C dynamic libraries and properly call out to their functions performing all the required data setup. See this for more info.

    Python's ctypes module implements exactly this approach.

It's harder for me to classify Java's JNI and .NET's P/Invoke into these two categories. May be they sit somewhere in the middle.

Community
  • 1
  • 1
kostix
  • 51,517
  • 14
  • 93
  • 176
  • Yes. I believe the the implementation of the APIs like open/close would set things up (parameters to be shared, return stack pointer etc) and have some assembly code to send s/w interrupt (e.g. trap) to cpu. In case of a C program, these libraries will be loaded and called at run time just like any .so. So, if the first route (libc) is taken, how are libc functions invoked from python/java?) – tan Oct 13 '14 at 11:16
  • @tan, updated my answer to address the question in your comment. – kostix Oct 13 '14 at 12:54
2

In other languages this is usually (always?) achieved with a wrapper around the native function calls. In reality, it looks something like this. LanguageX -> Wrapper -> Native Code(C/C++)

Sometimes this wrapper takes the form of an entire framework, such as in JNI for java. which also works great for Groovy scripts.

With some languages you can load native DLLs directly into your application in a way similar to C/C++. This is true in the the case of Python using ctypes.

Other times, native calls aren't needed at all and the same result can be produced directly using your language of choice. Cross-platform GUI toolkits are one small example where native OS calls can be replaced completely. Such as with GTK or QT

Hope that clears things up a bit :) Let me know if you'd like any other language-specific details.

Justin
  • 1,972
  • 13
  • 28
  • 1
    I don't think Python is closer to C than Java is in any useful sense. – svick Oct 10 '14 at 14:21
  • Thanks, I only meant that it was closer to C in the sense that you can load native dlls directly. Edited for clarification. – Justin Oct 11 '14 at 02:48
  • Thanks. This is what I was looking for. Although, it would be interesting to know how exactly does wrapper works. – tan Oct 13 '14 at 11:29
  • That would be rather in-depth and slightly outside the scope of the question. See [Wrapper library](http://en.wikipedia.org/wiki/Wrapper_library). In this case the wrapper library would be some form of native interface. kostix answer describes how this all works internally, while my answer is more of a general overview from a user perspective. – Justin Oct 13 '14 at 20:30