beihl@cadillac.CAD.MCC.COM (Gary Beihl) (01/03/89)
Thanks to those who responded to my recent inquiry regarding dynamic loading. What follows is a summary of what I've learned. It is indeed possible to dynamically load .o files under the Apollo version of BSD Unix (SR10.0). There are a few gotchas however, which keep us from using it in our application. First, the .o file to be loaded has to be compiled with the "-pic" (position-independent code) option. This can be done under BSD by specifying -W0,-pic to /bin/cc. I believe some performance penalty is paid when using this option due to an extra level of indirection. Second, use the loader_$load() call to access the system loader. With the proper setting of options to this function, one can lookup symbols and execute functions in the new code. The rub comes when the new object tries to reference symbols in the original executable. You can't (by default). It was suggested to me that I redefine main() to be a stub which dynamically loads the entire program, thus making all symbols known. Unfortunately, this means everything must be compiled with -W0,-pic. The loader kept telling me there was some part of my main program requiring linking (I assume this meant not compiled with -pic). The `file' command does not distinguish -pic from normal code. Perhaps some of the system libraries were being complained about. I *did* compile all the application code with -pic. It seems to me that a better solution to this problem is to have an incremental option on the linker. The BSD interface does not provide one. Perhaps it's possible under AEGIS. I don't think so. Incremental linking eliminates the need for position independent code, since the code can be custom-relocated to the virtual address specified by the loading application. -- Gary Beihl (beihl@mcc.com)
oj@apollo.COM (Ellis Oliver Jones) (01/08/89)
In article <685@cadillac.CAD.MCC.COM> beihl@cadillac.CAD.MCC.COM (Gary Beihl) writes: >[To be dynamically loaded...] the .o file to be >loaded has to be compiled with the >"-pic" (position-independent code) option. This can be done >under BSD by specifying -W0,-pic to /bin/cc. I believe some >performance penalty is paid when using this option due to >an extra level of indirection. There's no big performance penalty. All the library code is compiled this way, so the generated code when you specify -pic is in no way second class. >The rub comes when the new object tries to reference symbols >in the original executable. You can't (by default). We often solve this kind of problem by formalizing the interface between separate executables in the form of an entry point vector (epv). An epv is an array of procedure pointers. If module A dynamically loads module B, we then arrange to pass the entry point vector (or a pointer to it) from module A to module B. Then when B calls back to A, it calls through the epv. Obviously, you have to alter the structure of your application to use this technique, so it may not help you. >It seems to me that a better solution to this problem is to >have an incremental option on the linker. The BSD interface >does not provide one. Object modules and executables are indistinguishable. It is possible to link any pair of modules together via either /bin/ld or /com/bind . It's also unnecessary to use /bin/ld or /com/bind at all on self-contained programs; the C runtime library and most other "system subroutines" live in global libraries, and therefore are present in your address space already. Just run the .o or .bin file! You might exploit the uniformity of objects and executables by using a shell script to link together your "main" module and one of several optional modules, then execute the result, then delete it when you're done executing it. This could give you what you're looking for. Beware: you CAN'T bind together two cmpexe files to produce a third. You may also be able to use custom libraries to advantage. A library is any object code compiled -pic . You can use the /com/inlib command to install a library into a process. You can also create a global library, and have it loaded at node-boot time by calling it /lib/userlib.global . (In global libraries, beware; all read-write static data is initialized to zero, regardless of what kind of initialization you ask for.) Global libraries save much space and time when the same code is running in many different processes. They're quite painful to debug, though, so be careful. If you're interested in dynamic code loading, you should take a look at the "Extensible Streams Toolkit" manual as well. You should also look at that manual if you're curious about the purpose of all the stuff in /sys/mgrs . On another subject, I understand that the next release of the PRISM (DN10000) operating system will have a maximum process count of at least 150, and will use substantially less than 1/2 megabyte of backing store (disk space) per process. The current numbers are 56 (user processes) and approx. 5 megabytes, so this is a big improvement. /Ollie Jones (speaking for myself, not necessarily for Apollo Computer, Inc.) (get the details right! check the manuals before trying any of this!)
oj@apollo.COM (Ellis Oliver Jones) (01/09/89)
In my previous article <40b9f17f.d5b2@apollo.COM> oj@canyon.UUCP I made a lot of mistakes. Everyone would be better off disregarding the article entirely. So sorry. I'll try to do my homework better next time. /oj