Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > alt.os.development > #8240
| From | "Rod Pemberton" <boo@fasdfrewar.cdm> |
|---|---|
| Newsgroups | alt.os.development |
| Subject | Re: How to bind HLLs to OS calls |
| Date | 2015-06-23 19:24 -0400 |
| Organization | Aioe.org NNTP Server |
| Message-ID | <op.x0phzqyjyfako5@localhost> (permalink) |
| References | <mls29c$b0q$1@dont-email.me> <op.x0ewr50gyfako5@localhost> <mluuql$4cc$1@dont-email.me> <op.x0g2zlo8yfako5@localhost> <mm9qnb$cnb$1@dont-email.me> |
On Mon, 22 Jun 2015 16:22:19 -0400, James Harris
<james.harris.1@gmail.com> wrote:
> "Rod Pemberton" <boo@fasdfrewar.cdm> wrote in message
> news:op.x0g2zlo8yfako5@localhost...
>> On Thu, 18 Jun 2015 13:24:52 -0400, James Harris
>> <james.harris.1@gmail.com> wrote:
>>> "Rod Pemberton" <boo@fasdfrewar.cdm> wrote in message
>>> news:op.x0ewr50gyfako5@localhost...
>>>> On Wed, 17 Jun 2015 11:05:30 -0400, James Harris
>>>> <james.harris.1@gmail.com> wrote:
>>>>> (I don't want to call my OS functions directly as that would limit
>>>>> application source code to one specific means of getting to the
>>>>> kernel,
>>>>
>>>> Why is that an issue?
>>>
>>> Two reasons:
>>>
>>> 1. A given version of the kernel may be invoked by a software
>>> interrupt or SYSENTER or SYSCALL or a far call or something else.
>>> They are all hard or impossible to write in C or another HLL, and the
>>> best approach may change.
>>>
>>> 2. Some OS calls may be satisfiable without taking the trip to
>>> privleged mode. In that case it makes sense to have the subroutine
>>> which is immediately called by the app just do the work necessary and
>>> return without invoking the kernel.
>>
>> By "call my OS functions directly," I thought you meant something like:
>>
>> call_my_OS(0xNN);
>
> Not quite but I can now give you an example of the intention
Ok.
> Here is a way I have worked out to call a couple of OS functions (from
> C) that certainly heads a good way in the direction I want to go. It is
> not a complete solution but it illustrates the kind of thing that I am
> trying to do. I only worked this out last night and so far ISTM a really
> exciting step forward!!!.
>
> Can you see how it is supposed to work and what I am trying to achieve?
Not to be pedantic, but you have yet to explain it here. It's below.
So, I'll copy the question down below. (Ok. I answered it too.)
> I will put some explanatory comments below the code but basically there
> is to be a struct (declared in the header) where each member is a
> pointer to an OS function, and that structure ends up being called "os"
> in the body of the code. See the part "Issue some OS calls" for how I am
> thinking apps will call the OS.
The idea seems clean to me. It's easier than a library. You can
always add more to the end of the struct and keep #defines for the
number of OS calls available or the struct version. I.e., to allow
for backward compatibility with future changes.
Are these functions to just be extern's?
> #define os oscalls_v0dev
> #include "oscalls_v0dev.h"
>
> int apptest2(void) {
>
> /* Issue some OS calls */
> os.qret(); /* Quick return */
> os.kret(); /* Kernel return */
>
> /* Successful completion */
> return 0;
> }
>
Are there to be just the two calls with kernel following quick,
i.e., is there a specific order or implementation here? Or,
is this example just supposed to be a mix of whatever calls are
required to implement an app?
(I'm assuming that the latter question is true, but I'm being
a bit pedantic.)
> I like this approach because:
>
> * it makes OS calls easy to use without mixing them into the language's
> library
>
> * the compiler does not need to know anything about the OS. All it needs
> to know is what it sees in the OS-supplied header
>
> * OS calls will be fast and, despite the indirection, can be branch
> predicted (more on that below)
>
> * the call table can be created dynamically, if appropriate (I think! -
> work to do here)
...
> * it gives OS calls their own namespace.
That could be done with underscores or dollar sign symbol too, but
three characters for "os." is short and sweet.
> It was the quest for a namespace which led me to the idea of the struct.
> The namespace/struct ensures OS function names will not conflict with
> any others that appear in the program.
Well, as long as no one happens to use "os", but the odds of that
IMO are low and it's easy for them to adjust their code.
> The idea is that this function, apptest2, wants to make a couple of
> calls to an OS and expects the OS to provide a certain call interface
> version or API. In this case I have called it v0dev for Version 0,
> Development branch, but the name can be longer or shorter. The idea of
> versioning is that apps written for an older version of the OS API can
> still be run on a newer OS and that the OS can be upgraded without
> breaking old apps, as long as it retains the ability to service older
> API versions.
So, the next version might be v1dev, then v2dev, etc.?
Have you considered an integer passed as the first parameter to
indicate the expected version of the function? Then, it can
always be named "vdev.h". E.g.,
#define os oscalls_vdev
#include "oscalls_vdev.h"
/* in oscalls_vdev.h */
// #define VERSION 0
int apptest2(void) {
/* Issue some OS calls */
os.qret(VERSION, ...); /* Quick return */
os.kret(VERSION, ...); /* Kernel return */
/* Successful completion */
return 0;
}
qret and kret won't be C style "void func(void)"
anymore, which isn't a problem for C, but may
complicate your assembly, Pascal, Fortran, etc goals.
> Because the specific version name can be long I used the #define to give
> it a shorter name. The short name can then be used later in the code
> when making the calls.
>
> The #include brings in the appropriate headers for the version the code
> expects to use. Within the included file is this line:
>
> extern struct oscalls_v0dev oscalls_v0dev;
>
> That declares oscalls_v0dev (which later gets called just os) as the
> table of function pointers where each pointer points to the appropriate
> routine. There will be one pointer for each OS service that the app can
> call. Here is an example struct declaration with just three calls in it.
> The real one would have many calls to the OS.
>
> struct oscalls_v0dev {
> void (*qret)(void); /* Quick return with no effect */
> void (*kret)(void); /* Kernel return with no effect */
> unsigned (*build_id)(void); /* Return the OS build version */
> };
The only question I have is whether or not the extern struct
and function pointers, which are intended for C here, will
also be compatible with assembly, Pascal, Fortran, etc in
terms of layout and format. Hopefully, that is a: "Yes."
> The key intention here is that this is implemented as an array of
> pointers (where each pointer has the same size), but from the C
> perspective each pointer has a particuar type, and the compiler will
> know what that type is. It can therefore use the type to ensure that
> calls to each routine have the correct parameters.
>
> Being a struct, too, each member has its own name. Despite being
> [implemented] as an array, C programs can therefore call each OS
> function by name and the compiler will match the types.
Well, an array would be indexable by an integer. If you used a
union, you could possibly use both names and an index to each call.
Alternately, if you used an array of function pointers, you
could do something like the following. Then, you could access
the function pointers by index or by name.
// tested code.
// Well, GCC 4.7.2 on Linux likes it ...
#include <stdio.h>
#define OS(n) os[ ## n ## ]
typedef void (*osfn)(void);
// would be extern
void hello()
{
printf("Hello ");
}
// would be extern
void world()
{
printf("World!\n");
}
// array of pointers to functions
// would be extern in your OS header
osfn os_table[]=
{
hello,
world,
NULL
};
#define os_qret() (*(os_table[0]))()
#define os_kret() (*(os_table[1]))()
int main(void)
{
(*(os_table[0]))();
(*(os_table[1]))();
os_qret();
os_kret();
return(0);
}
Unfortunately, you can't use a '.' dot, in the #defines
for "os.qret" etc., AFAIK, but you could ensure a more
exclusive "namespace" with underscores, e.g., os_qret__();
> Can you see how it is supposed to work and what I am trying to achieve?
Yes and I hope so. ;-)
>>> 2. Some OS calls may be satisfiable without taking the trip to
>>> privleged mode. In that case it makes sense to have the subroutine
>>> which is immediately called by the app just do the work necessary and
>>> return without invoking the kernel.
>>
>> If you don't have to invoke the kernel, do these constitute an OS
>> function?
>
> I would say so, yes. IMO any service routine that the OS provides is an
> OS function. How it provides it is not so important.
If these are an OS function, should you provide them to the user?
You just answered that it's acceptable to do so, but I'm thinking
about portability and safety, which seem to be of importance to you.
For portibility, using the functions would likely make the users
code non-portable since they are host specific functions. Whereas,
if the user only had access to kernel functions, they would have to
code their own equivalent to the OS function in portable code.
As for the safety issue, if a function isn't a kernel function,
how does the OS ensure that the function hasn't been replaced
by malicious code? ... I.e., that function is essentialy a
built-in man-in-the-middle attack waiting to happen. Isn't it?
> Some functions may be able to do what they have to do without privilege
> such as functions to read a certain time clock.
I can't immediately "see" how that would allow for software hacking,
but I immediately realize that could be used for hardware hacking.
This issue may be way outside the scope of your needs at this point.
E.g., an electrical engineer or someone familiar with both electronics
and programming could write code to read and write the hardware clock.
However, they've also installed hardware, logic circuitry, that
redirects the I/O to port address to the addresses they desire to hack.
> Other functions may *sometimes* be able to complete without going into
> kernel mode and other times need to go into kernel mode. For example, if
> told to read the next 2 bytes from a file, if there are 2 bytes buffered
> then that request can be satisfied without a kernel call. Otherwise the
> routine has to invoke the kernel to ask for more data.
Ok.
> I'll have to get back to you separately about the rest of the things we
> were discussing but I said I would comment on the performance of calls
> to the OS and branch predictability. Code speed is always exciting,
> right! I understand that x86_32 indirect near calls can be branch
> predicted. The apptest2 subroutine above compiles on x86_32 with -O2 to
> the following (gcc AT&T format with destinations on the right).
>
> push %ebp
> mov %esp,%ebp
> sub $0x8,%esp
> call *0x0
> call *0x4
> xor %eax,%eax
> leave
> ret
LEAVE? ...
Was there an ENTER somewhere? Or, is there some missing prologue (UK) or
prolog (US) code which would require LEAVE?
Also, IIRC, LEAVE is "slow." Avoid.
> The thing to note is the two calls to the OS. Both are simple (indirect)
> calls and need no special registers or addresses or parameters to be set
> up. They have apparently been compiled to be indirect via the struct
> mentioned above.
...
> Being near they should both be branch predictable and just as fast as
> ordinary calls.
The branch address is stored in memory, which can be modified.
I.e., this shouldn't be predictable on older processors since
it's not a fixed value that's part of the actual instruction
byte stream, but as long as the address doesn't change, it
should be predictable on the newer processors with a BTB, AISI,
since that location should generally remain fixed and be cached.
Like I said once before, I haven't followed processor design
since the mid 1990's and so Wikipedia and Google and AMD/Intel
manual are my main methods of slowly keeping up to date when
neded.
Sigh, apparently, this topic was from one of the other a.o.d.
or c.l.m. threads I haven't gotten too, and simply may not
due to life ...
Rod Pemberton
--
It's time to put an end to gun violence!
Use a hammer ...
Back to alt.os.development | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread
Re: How to bind HLLs to OS calls "Rod Pemberton" <boo@fasdfrewar.cdm> - 2015-06-18 02:10 -0400
Re: How to bind HLLs to OS calls "Rod Pemberton" <boo@fasdfrewar.cdm> - 2015-06-19 06:19 -0400
Re: How to bind HLLs to OS calls "James Harris" <james.harris.1@gmail.com> - 2015-06-22 21:22 +0100
Re: How to bind HLLs to OS calls "Rod Pemberton" <boo@fasdfrewar.cdm> - 2015-06-23 19:24 -0400
Re: How to bind HLLs to OS calls "Rod Pemberton" <boo@fasdfrewar.cdm> - 2015-06-24 22:15 -0400
Re: How to bind HLLs to OS calls "James Harris" <james.harris.1@gmail.com> - 2015-06-24 07:55 +0100
Re: How to bind HLLs to OS calls "Rod Pemberton" <boo@fasdfrewar.cdm> - 2015-06-24 21:00 -0400
csiph-web