|
|
>> I see. So you still have to manually define what needs to be linked
>> somehow?
>
> Lets just say I'm working with source files right now where the line
> used to compile the file takes up more than one screen of text in the
> editor.
Yes. For some reason, this seems to be mandatory in all Linux
development. I'm not sure why...
>> - When main.c is compiled, it produces main.o, which contains several
>> references to a foo() that should exist somewhere, but we don't know
>> where yet.
>
> No. Only if main() actually calls foo().
One assumes that if you don't need foo(), you wouldn't bother including
the header file. But sure, if the header declares a few dozen functions;
you might not call every single one of them.
>> - The linker takes main.o and foo.o, and replaces every jump to foo()
>> with a jump to an actual machine address. The resulting program is
>> actually runnable.
>
> Sort of. That's called "linking." Then there's "loading", which is when
> you put it into memory and *again* adjust a bunch of addresses.
Right. So what you're saying is that there's actually a second linking
stage each time final executable is run?
>> What I can't figure out is what happens if foo() is actually a
>> function somewhere in the OS kernel.
>
> It isn't. The read() function in C, for example, is in the C runtime
> library (glibc or uclibc on Linux). The linker always searches that
> library as part of the linking process (unless you're doing something
> funky like compiling the kernel). The read() function in that library is
> written in assembler (because C is really not very useful for this sort
> of work) and that assembler code copies items off the stack into machine
> registers and then invokes an assembler instruction that causes the CPU
> to set certain flags in the CPU registers that control permissions,
> change memory maps, and eventually winds up branching to a particular
> address in memory which the kernel has previously set to be a branch
> instruction to the code to handle read(). So read() is normal, except
> it's in a library the compiler always searches and contains assembly
> language.
In summary... you can't call the OS from C. You can only write C wrapper
functions around the assembly code that calls the OS. (And the wrapper
then of course looks like a normal C function...)
>> Presumably in each version of the kernel, the base address of this
>> function is going to be different... so how the hell does the linker
>> know what it is?
>
> It doesn't. It executes a machine-code instruction that's essentially a
> software interrupt. (That's why you see things like DOS functions being
> described as "Int 21h" functions.)
>
> It's an instruction that invokes an indirect branch.
I see. So that's the mechanism on the IA32 platform, is it? (I thought
only the BIOS uses this method...)
>> The way this works on the Amiga is that you can't just *call* an OS
>> function.
>
> There's no memory protection or kernel mode on AmigaOS. It can't be
> multiuser.
Interestingly enough, the Motorola 68000 does in fact have two modes of
operation: "user mode" and "supervisor mode". I have no idea what the
distinction is.
Additionally, the factory-standard Amigas had the "EC" version of the
Motorola 68000 CPUs which lack an MMU. You can, however, replace this
with a version of the CPU that possesses an MMU. Indeed, several
companies offered the add-on boards, together with the necessary
software to extend AmigaOS to support virtual memory. This suggests that
the MMU-enabled variant of the CPU could support memory protection if
you wanted.
And finally, it's perfectly possible to make a multiuser OS without
memory protection. It just won't have any memory protection. (Meaning
one rogue program can crash the whole system.) Arguably not very useful,
but completely doable.
Post a reply to this message
|
|