Mode-Independent Macros

If you want to write assembly code that runs both in 32-bit PowerPC and 64-bit PowerPC environments, you must make sure that 32-bit–specific code runs in 32-bit environments and 64-bit–specific code runs in 64-bit environments. This appendix introduces the macros included in the OS X v10.4 SDK to facilitate the development of assembly code that runs in both environments.

The mode_independent_asm.h file in /usr/include/architecture/ppc defines a set of macros that make it easy to write code that runs in 32-bit PowerPC and 64-bit PowerPC environments. These macros include both manifest constants and pseudo mnemonics. For instance, the GPR_BYTES constant is either 4 or 8 (the size of the general-purpose registers). And lg pseudo mnemonic expands to lwz in a 32-bit environment or ld in a 64-bit environment. The header file documents all the macros in detail.

For example, the 32-bit code to get a pointer at offset 16 from GPR15 into GPR14 is:

    lwz r14,16(r15)

The 64-bit code is:

    ld r14,16(r15)

One way to support both environments is by using conditional inclusion statements. For example, the following code uses __ppc64__ to determine whether the program is running in 64-bit mode and executes the appropriate statement:

#ifdef __ppc64__
    ld r14,16(r15)
#else
    lwz r14,16(r15)
#endif

However, a simpler way is to use the lg pseudo mnemonic, as shown here:

#include <architecture/ppc/mode_independent_asm.h>
    ...
    lg r14,16(r15)

If you write code that invokes functions that may be relocated, you may need to create a lazy symbol pointer in 32-bit code similar to this:

    .lazy_symbol_pointer
L_foo$lazy_ptr:
    .indirect_symbol _foo
    .long dyld_stub_binding_helper

The assembly sequence for is as for 64-bit code is similar to the 32-bit code, but you need to ensure you allocate an 8-byte space for the symbol, using .quad instead of .long, as shown here:

    .lazy_symbol_pointer
L_foo$lazy_ptr:
    .indirect_symbol _foo
    .quad dyld_stub_binding_helper

Using the g_long mode-independent macro instead of .long or .quad, you can write a streamlined dual-environment sequence without adding an #ifdef statement. The mode-independent sequence would look like this:

#include <architecture/ppc/mode_independent_asm.h>
    ...
    .lazy_symbol_pointer
L_foo$lazy_ptr:
    .indirect_symbol _foo
    .g_long dyld_stub_binding_helper