Path: utzoo!attcan!uunet!pdn!alan From: alan@pdn.UUCP (Alan Lovejoy) Newsgroups: comp.sys.mac.programmer Subject: Re: Goin' Crazy on a Mac, or, How I Love MPW "GlobalData" Message-ID: <3128@pdn.UUCP> Date: 13 May 88 03:50:14 GMT References: <4625@batcomputer.tn.cornell.edu> <6333@cit-vax.Caltech.Edu> Reply-To: alan@pdn.UUCP (0000-Alan Lovejoy) Organization: Paradyne Corporation, Largo, Florida Lines: 105 In article <6333@cit-vax.Caltech.Edu> wetter@tybalt.caltech.edu.UUCP (Pierce T. Wetter) writes: > Actually this is common to all languages under MPW. Global data is >referenced as an offset from a5. On the 68000 thats 16 bits, on the 020 its >32 bits. Read the object code format description if you want more details. >I agree it can be annoying, but there are some things to remember. > ... The real problem is that the 68000 can only have >a 16 bit offset from a5. Note that the limit should be 64K and a5 should point >to the center of your data, but no compiler writers are smart enough to think >of that. Using A5 as the global frame pointer is standard practice on 68k systems. If effect, A5 is being used as a "segment register". Global variables are referenced using 16-bit *signed* displacements from the address in A5. This allows for easy relocation of the static data, and simplifies the linking process. The size of this displacement on the 68020 is also 16 bits (if the register indirect with displacement addressing mode is used). The code to add two global int variables into a third automatic variable would be: -- 68k assembly -- -- pseudo-C -- MOVE.L var1(A5),D0 ;D0 = *(A5 + var1) ADD.L var2(A5),D0 ;D0 += *(A5 + var2) MOVE.L D0,var3(A6) ;*(A6 + var3) = D0 It's true that the 68020 can have a 32-bit displacement from an address register, but it involves an addressing mode not available on the 68k. If you use that adressing mode, your code won't run on an mc68000 or mc68010. Also, the displacement immediately follows the instruction and takes up either 16 or 32 bits of memory. It has to be fetched by the processor as part of the instruction stream. It takes more cycles to fetch 32 bits than it does to fetch 16 bits (or else it uses up space in the pipeline that could otherwise have been used for additional work). And the 'address register indirect with 32-bit displacement' addressing mode requires 32 bits JUST FOR THE INSTRUCTION, plus another 32 bits for the displacement. Most 68k instructions fit in only 16 bits, apart form offsets and immediate (constant) values. Still, in many cases this may be a good solution for MacII owners or developers. There is a well-known technique that can and should be used by Mac compilers to 'break the 32k barrier'. Actually, there are several, but let me outline my favorite one: Imagine you are a linker stitching together an executable from a collection of object modules. You notice that one of the data structures in static (global) storage is a megabyte in size. If this is the only object in static storage, there is no problem. There is also no problem if the total size of the other global objects is less than 32k (or 64k if you're semi-intelligent). But what do you do when you encounter a second global object a megabyte in size? Let's assume that there are only two global objects, each one megabyte. The base address of the first will be put into A5. Where can we store the base address of the second so that the program can find it? We could assign another register to such duty, but we only have 8 address registers, one of which is already being used (by the hardware!) as the top-of-stack pointer, another must be used as the local frame pointer, two must be free at all times as work-registers, A5 is already spoken for, leaving only two "free" address registers (if you think this is a cramp, try programming an Intel CPU). Using extra registers can give us 192k of global memory space, but the cost is rather high because those address registers are needed for more efficient pointer and array manipulation. You probably wonder why the compiler didn't provide a fix for your problem, so that you (the linker) wouldn't have to. The C compiler *can't* fix this problem, because the C compiler usually can't see the program as a whole, but only a function or so at a time. It can't possibly know the total size of the global data, since each function linked in can declare its own global data without asking permission of the "main" function or any other. There is a reason why Pascal programs are structured the way they are! No, I'm not suggesting you switch to Pascal (or Modula-2, or Ada, or..). So even if you (the linker) decide to allocate additional address registers as global data pointers, you have yet another nasty problem: you'll have to go through each object module and fix all references to A5 so that they refer to the register you have chosen as the pointer to the segment containing the object being referenced by that instruction. Unfortunately, all the solutions suffer from this problem. The goal is to make such fix-up jobs as painless for the linker as possible. In my opinion, the best technique is as follows: instead of storing the data for the second megabyte-sized object at some offset from A5, store its address there instead. In other words, the linker can create a segment table or object table which is stored somewhere +/- 32k bytes from A5. So the 500000th byte of megabyte object #2 would be accessed thusly: MOVE.L bigObjectAddrsess(A5), A4; move the base address of a large ; object into register A4 MOVEI.L #500000,D0 ; initialize D0 to 500000 MOVE.B (A4,D0),D1 ; move the 500000th byte of the large ; object to register D1 This requires an additional 16-bit instruction with a 16-bit offset field (32 bits total) be inserted into the code by the linker for referencing the largest global objects (the smaller objects should be given first priority for allocation in the "main" segment). Hopefully, some compiler/linker suppliers will be moved to work on this problem. -- Alan Lovejoy; alan@pdn; 813-530-8241; Paradyne Corporation: Largo, Florida. Disclaimer: Do not confuse my views with the official views of Paradyne Corporation (regardless of how confusing those views may be). Motto: Never put off to run-time what you can do at compile-time!