[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

3. Special projects

When you compile and link using the default options, the size of your application's code is limited to 32K. The 68000 DragonBall processor can only make a relative jump if it is of a distance of 32K or less, and you will get errors from the assembler and/or linker if your code attempts to jump further than that. The default size limit, enforced at link time, is such that it is possible to jump arbitrarily within a maximally sized code resource without risking attempting an impossibly long jump.

While the default is limited, it is certainly possible to create larger applications; the choices and issues involved are discussed in this chapter.

Also discussed are other types of projects: shared libraries and various flavours of stand-alone code resources, particularly HackMaster Hacks and Palm OS 5 armlets.

3.1 Size limitations for a single code resource  
3.2 Multiple code resources  ...and how to escape them.
3.3 Shared libraries  Creating and using shared libraries.
3.4 Stand-alone code resources  Hacks, armlets, etc.


3.1 Size limitations for a single code resource

Even though the processor is unable to make a relative jump directly between the extremities of a code section larger than 32K, it is still possible to use such a code section if you are willing to indulge in manual heroics to help the compiler avoid needing to make such an extreme function call.

Note that a code section corresponds to a code resource in your project's final Palm OS database, and the maximum size for any kind of resource is still limited to approximately 64K by the Palm OS memory manager and the HotSync protocol.

Some of the heroic techniques are:

The maximum size of the main code section is specified in the linker script and enforced during linking (see section `Linker Scripts' in Using ld). You can override the default script's 32K size by using a -T script linker option in your link command. Two suitable linker scripts, which can be used as is or copied and modified, are already provided, both allowing a .text section of up to approximately 64K:

-T text_64k
Up to 64720 bytes, the maximum resource size supported by all versions of Palm OS to date.

-T text_64k_palmos3
Up to 65505 bytes, the maximum supported by Palm OS version 3.0 and higher.

There is, of course, some risk in going right up to the maximum resource size limits. In practice, the limit has typically been increasing with each new version of Palm OS, and has never decreased. Nonetheless, it may be wise to use text_64k even if you plan to target only Palm OS 3.0 and higher devices.


3.2 Multiple code resources

Theoretically, the heroics required to make functions calls over a distance of more than 32K are applicable for an arbitrarily large code resource. Unfortunately each resource is still limited to only 64K by the HotSync protocol, at least on Palm OS versions up to and including Palm OS 4.1. Thus the gain compared to a hassle-free 32K code resource is not great, and the best way to allow an application to increase beyond 32K of code is to allow it to have multiple separate code resources.

One simple technique for producing multiple code resources is to map distinct GCC code sections into distinct Palm OS code resources. This version of prc-tools implements a limited form of that: functions may be marked as being in particular sections via the standard GCC section attribute (see section `Declaring Attributes of Functions' in Using and Porting GCC). (These markings are used quite early in the compiler, so other ways of putting functions into different sections, such as -ffunction-sections and rearrangements at link time, don't work.)

A project definition file (see section 4. Definition files) must be used, with a multiple code clause to inform build-prc of the new sections. You also need to define the pointer variables mentioned above in an assembly language stub file linked into your executable, and should use a linker script to place the new sections at appropriate addresses. The easiest way to do these things is to use multigen to generate them from the same definition file clause (see section 6.2 multigen).

3.2.1 Multiple code resources and global data  But especially without globals
3.2.2 Breaking up an existing application  


3.2.1 Multiple code resources and global data

The current implementation puts pointers to the code resources into the application's global data, and uses those pointers in the code emitted for each call in which the calling function and the called function are in different sections. This means that you must not attempt to call between different sections when globals are not available.

In particular, all functions in your application called while processing a launch code that doesn't give you globals must be in the main code section. This always includes PilotMain, which is always called by the startup code for all launch codes.

Read-only data

Read-only data, such as string literals and other constant data, are put into code sections rather than the global data section. This saves global data space, which is in short supply, and is valid since the data, just like the code resources that contain them, are read-only.

When an item of read-only data has file or global scope, it will be placed in the main code section. When it is local to a function, it will mostly, but not always, be placed in the same code section as that function.

GCC's optimizer will usually notice when a string literal (or other constant) is identical to one which has been previously emitted, and will reuse the storage previously emitted rather than reserving more space for a duplicate.

Thus, in the following example, when optimisation is on, the string literal referenced from bar may well be in the foosec section, while bar itself is in the main code section:

 
const char *foo () __attribute__ ((section ("foosec")));
const char *foo () { return "hello world"; }
const char *bar () { return "hello world"; }

The code emitted for such a reference is similar to that emitted for an inter-section function call: when there is a data reference in which the referring function and the referenced item of read-only data are in different sections, the code emitted uses the item's code resource's pointer, which is located in the application's global data.

This means that you must ensure that this sort of reference doesn't occur when globals are not available. Because this compiler optimisation (of course) occurs only within a single translation unit, a sufficient (but not necessary) way to ensure this is by placing functions which are in different sections in different translation units (e.g., in separate `.c' files).

In particular, all read-only data referenced while processing a launch code that doesn't give you globals must be in the main code section. (Thus, in the example above, bar is likely to crash if it is called during a no-globals launch.)

This can be arranged in the following ways, amongst others:


3.2.2 Breaking up an existing application

To use multiple code resources in an existing application, you need to do the following:

  1. If your Makefile uses obj-res, change it to use build-prc directly on your bfd executable. For example, from an original

     
    myapp.prc: code0000.myapp.grc ...
            build-prc ... *.myapp.grc ...
    
    code0000.myapp.grc: myapp
            m68k-palmos-obj-res myapp
    

    remove references to .grc files, and delete the obj-res rule altogether:

     
    myapp.prc: myapp ...
            build-prc ... myapp ...
    

  2. Choose functions to be placed in other code sections, and annotate their declarations:
     
    #define EDIT_SECTION  __attribute__ ((section ("editfns")))
    
    void EditFormHandler (...) EDIT_SECTION;
    void DrawEditForm () EDIT_SECTION;
    
    (This also demonstrates using a macro to ease moving several functions at once.)

    Make very sure that the relevant annotated declaration is visible when you define such a function, and especially everywhere you call it. If there is a call to a non-default sectioned function from which the annotated declaration is not visible, the call will be generated as a call to the default code section. When such a call is executed, it jumps to effectively a random location in the wrong code section and almost certainly crashes. (Warning options which can detect these mistakes at compile time are noted in the discussion of required visibilities in 1.2 Function attributes.)

    Note that COFF only stores eight character of a section name: if your section names are any longer than this, they will be truncated, leading to trouble.

  3. Add a multiple code clause to your definition file:

     
    multiple code { "editfns" }
    

    Or, if you're not already using a definition file, write one including such a clause and use it in your build-prc command:

     
    myapp.prc: myapp.def myapp ...
            build-prc ... myapp.def myapp ...
    

  4. Add rules to your Makefile to generate and build the assembler stub and linker script.

     
    myapp-sections.o: myapp-sections.s
            m68k-palmos-gcc -c myapp-sections.s
    
    myapp-sections.s myapp-sections.ld: myapp.def
            m68k-palmos-multigen myapp.def
    

  5. Link the assembler stub into your bfd executable, and use the linker script to place the extra code sections at appropriate addresses.
     
    OBJS = ...list of object files... myapp-sections.o
    
    myapp: $(OBJS) myapp-sections.ld
            m68k-palmos-gcc -o myapp $(OBJS) myapp-sections.ld
    


3.3 Shared libraries

(This section has not yet been written; see 6.3 stubgen, and also the library projects in the sample code collection.)


3.4 Stand-alone code resources

Normally build-prc processes a bfd executable as a full-blown executable, converting its .data, .bss, and .text and any other code sections into the corresponding Palm OS resources, as appropriate.

However if the bfd executable contains certain sections that are special to build-prc, its .text section will be converted into a stand-alone code resource instead, and the other sections listed above will be discarded (producing warnings) if present.

These "special sections" are .disposn (which is an abbreviation of disposition) and .trap. They are interpreted as follows:

Note that these two-byte integer fields are interpreted according to the native endianness of the bfd executable in which they occur.

Producing a stand-alone code resource

There is nothing special about compiling code that is to become stand-alone, other than that you must not use global data or any extra code resources, because stand-alone code, by definition, cannot have such things.

There are considerations at link time, related to the lack of startup code:

You can easily set up the special sections marking your code as stand-alone by using the following macros, provided in `Standalone.h':

STANDALONE_CODE_RESOURCE_ID (id)
Mark the executable as a stand-alone code resource with the specified id and a suitable resource type depending on the resulting compiled executable's architecture: `code' for 68000 or `armc' for ARM.

STANDALONE_CODE_RESOURCE_TYPE_ID (type, id)
STANDALONE_CODE_RESOURCE_TYPESTR_ID (type, id)
Mark the executable as a stand-alone code resource with the specified resource type and id. If you specify type with a multicharacter char constant (`'TYPE''), use the ...TYPE... macro; if you use a string (`"TYPE"'), use the ...TYPESTR... version.

HACKMASTER_TRAP (vector)
Mark the executable as a stand-alone code resource, and add a TRAP resource containing vector, which may be any C constant expression, for example, a numeric constant or even a sysTrapfoo constant as defined in a Palm OS SDK's `CoreTraps.h'.


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]