[Back] [Top] [Next]

8 Linking Issues And Stack Placement

This causes some confusion, especially to those used to other compiler systems.

8.1 Basic Use Of L51 Linker

The various modules of a C program are combined by a linker. After compilation no actual addresses are assigned to each line of code produced, only an offset is generated from the start of the module. Obviously before the code can be executed each module must be tied to a unique address in the code memory. This is done by the linker.

L51, in the case of Keil (RL51 for Intel), is a utility which assigns absolute addresses to the compiled code. It also searches library files for the actual code for any standard functions used in the C program.

A typical invocation of the linker might be:

l51 startup.obj, module1.obj, module2.obj, module3.obj, C51L.lib to exec.abs

Here the three unlocated modules and the startup code (in assembler) are combined. Any calls to library functions in any of these files results in the library, C51L.lib, being searched for the appropriate code.

The target addresses (or offsets) for any JMPs or CALLs are calculated and inserted after the relevant opcodes.

When all five .obj files have been combined, they are placed into another file called EXEC.ABS, the ABS implying that this is absolute code that could actually be executed by an 8051 cpu. In addition, a "map" file called EXEC.M51 is produced which summarises the linking operation. This gives the address of every symbol used in the program plus the size of each module.

In anything other than a very small program, the number of modules to be linked can be quite large, hence the command line can become huge and unwieldy. To overcome this the input list can be a simple ASCII text file thus:


   l51 @<input_file>

where input_file = ;

   startup.obj,&
   module1.obj,&
   module2.obj,&
   module3.obj,&
   &
   C51L.lib &
   &
   to exec.abs

There are controls provided in the linker which determine where the various memory types should be placed.

For instance, if an external RAM chip starts at 4000H and the code memory (Eprom) is at 8000H, the linker must be given:

l51 startup.obj, module1.obj, module2.obj, module3.obj,
C51L.lib to exec.abs CODE(8000H) XDATA(4000H)

This will move all the variables in external RAM to 4000H and above and all the executable code to 8000H. Even more control can be exercised over where the linker places code and data segments. By further specifying the module and segment names, specific variables can be directed to particular addresses - see 2.1.8 for an example.

8.2 Stack Placement

Unless you specify otherwise, the linker will place the stack pointer to give maximum stack space. Thus after locating all the sfr, compiled stack and data items, the real stack pointer is set to the next available IDATA address. If you use the 8032 or other variant with 128 bytes of indirectly-addressable memory (IDATA) above 80H, this can be used very effectively for stack.

?C_C51STARTUP         SEGMENT   CODE ;Declare segment in indirect 
                                      area
?STACK                SEGMENT   IDATA; 

             RSEG     ?STACK         ; Reserve one byte 
             DS       1
             EXTRN    CODE (?C_START)
             PUBLIC         ?C_STARTUP
             CSEG     AT    0
?C_STARTUP:  LJMP     STARTUP1

             RSEG     ?C_C51STARTUP
STARTUP1: ENDIF
             MOV      SP,#?STACK-1 ; Put address of STACK 
                                     location into SP
             LJMP     ?C_START      ; Goto initialised data 
                                     section

8.3 Using The Top 128 Bytes of the 8052 RAM

The original 8051 design has just 128 bytes of directly/indirectly addressable RAM. C51, when in the SMALL model, can use this for variables, arrays, structures and stack. Above 128 (80H) direct addressing will result in access of the sfrs. Indirect addressing (MOV A,@R0) does not work.

However with the 8052 and above, the area above 80H can, when indirectly addressed, be used as additional storage. The main use of this area is really as stack. Data in this area is addressed by the MOV A,@Ri instruction. As only indirect addressing can be used, there can be some loss of efficiency as the Ri register must be loaded with the required 8 bit address before any access can be made.

Left to its own devices C51 will not use this area other than for stack. Unusually, the 8051 stack grows up through RAM, so the linker will place the STACK area at the top of the area taken up with variables, parameter passing segments etc.. If your application does not need all the stack area allocated, it is possible to use it for variables. This is simply achieved by declaring some variables as "idata" and using "RAMSIZE(256)" when linking.

Such is human nature that most people will not think of using idata until the lower 128 bytes actually overflows and a panic-driven search begins for more memory!

As has been pointed out, idata variables are rather harder to get at because of the loading of an Ri register first. However there is one type of variable which is ideally suited to this - the array or pointer-addressed variable.

The MOV A,@Ri is ideal for array access as the Ri simply contains the array index. Similarly a variable accessed by a pointer is catered for, as the @Ri is effectively a pointer. This is especially significant now that version 3.xx supports memory space specific pointers. The STACK is now simply moved above these new idata objects.

To summarise, with the 8052 if you are hitting the 128 byte ceiling of the directly addressable space, the moving of arrays and pointer addressable objects can free-up large amounts of valuable directly addressable RAM very easily.

8.4 L51 Linker Data RAM Overlaying

8.4.1 Overlaying Principles

One of the main tricks used to allow large programs to be generated within an 8051 is the OVERLAY function. This is a mechanism whereby different program variables make use of the same RAM location(s). This possibility arises when automatic local variables are declared. These by definition only have significance during the execution of the function within which they were defined. Once the function is exited the area of RAM used by them is no longer required. Of course static locals must remain intact until the function is next called. A similar situation exists for C51's reserved memory areas used for parameter passing.

Taken over a complete program, each function will have a certain area of memory reserved for its locals and parameters. Within the confines of an 8051 the on-chip RAM would soon be exhausted.

The possibility then arises for these individual areas to be combined into a single block, capable of supplying enough RAM for the needs of the single biggest function.

In C51 this process is performed by the linker's OVERLAY function. In simple terms, this examines all functions and generates a special data segment called "DATA_GROUP", able to contain all the local variables and parameters of all C51 functions. As an example, if most functions require only 4 byes of local data but one particular one needs 10, the DATA_GROUP will be 10 bytes long.

Using the registers as a location for temporary data means that a large number of locals and parameters can be accommodated without recourse to the DATA_GROUP - this is why it may appear smaller than you expect.

The overlayer works on the basis that if function 1 calls function 2, then their respective local data areas may not be overlaid, as both must be active at the same time. A third function 3, which is also called by 1, may have its locals overlaid with 2, as the two cannot be running at the same time.

            main
             |
            funcA - func2 - func3 - func4
             |
            funcB - func5 - func6 - func7
             |
            funcC - func8 - func9 - func10
             |  

As funcA refers to func2 and func2 refers to func3 etc., A,2,3 and 4 cannot have their locals overlaid, as they all form part of the same path. Likewise, as funcB refers to func5 and func6 refers to func7 etc., B,6,7 and 4 cannot have their locals overlaid. However the groups 2,3,4; 5,6,7 and 8,9,10 may have their locals overlaid as they are never active together, being attached to sequential branches of the main program flow. This is the basis of the overlay strategy.

However a complication arises with interrupt functions. Since these can occur at any time, they would overwrite the local data currently generated by whichever background (or lower priority interrupt) function was running, were they also to use the DATA_GROUP. To cope with this, C51 identifies the interrupt functions and called functions and allocates them individual local data areas.

8.4.2 Impact Of Overlaying On Program Construction

The general rule used by L51 is that any two functions which cannot be executing simultaneously may have their local data overlaid. Re-entrant functions are an extension of this in that a single function may be called simultaneously from two different places.

In 99% of cases the overlay function works perfectly but there are some cases where it can give unexpected results.

These are basically:

  1. Indirectly-called functions using function pointers
  2. Functions called from jump tables of functions
  3. Re-entrant functions (-incorrect or non-declaration thereof)

Under these conditions the linker issues the following warnings:

MULTIPLE CALL TO SEGMENT
UNCALLED SEGMENT
RECURSIVE CALL TO SEGMENT

8.4.2.1 Indirect Function Calls With Function Pointers

(hazardous)

Taking (i) first:

Here func4 and func5 are called from main by an intermediate function called EXECUTE. A pointer to the required function is passed. When L51 analyses the program, it cannot establish a direct link between execute and func4/5 because the function pointer received as a parameter breaks the chain of references - this function pointer is undefined at link time. Thus L51 overlays the local segments of func4, func5 and execute as if they were all references from main. Refer to the overlay diagram above if in doubt.

The result is that the locals of func4/5 will corrupt the locals used in execute. This is clearly VERY dangerous, especially as the overwriting may not be immediately obvious - it may only appear under abnormal operating conditions once the code has been delivered.


#include <reg517.h>
/***********************************************************  
***   OVERLAY HAZARD 1 - Indirectly called functions     ***
***********************************************************/
char func1(void) {    // Function to be called directly
 
char x, y, arr[10] ;

for(x = 0 ; x < 10 ; x++) {
   arr[x] = x ;
   }
 
return(x) ; 
}

char func2(void) {   // Function to be called directly
(.... C Code ...) 
}

char func3(void) {   // Function to be called directly
(.... C Code ...) 
return(x) ; 
}

char func4(void) {   // Function to be called indirectly


char x4, y4, arr4[10] ;      // Local variables 

for(x4 = 0 ; x4 < 10 ; x4++) {

   arr4[x4] = x4 ;
   }

return(x4) ; 
}

char func5(void) {   // Function to be called indirectly

char x5, y5, arr5[10] ;      // Local variables 

for(x5 = 0 ; x5 < 10 ; x5++) {

   arr5[x5] = x5 ;
   }

return(x5) ; 
}

/*** Function which does the calling ***/

char execute(fptr)  //Receive pointer to function to be used 
   char (*fptr)() ;
   {

   char tex ;       // Local variables for execute function
   char arrex[10] ;       

   for(tex = 0 ; tex < 10 ; tex++) {
      arrex[tex] = (*fptr)() ;
      }

   return(tex) ;
   }

/*** Declaration of general function pointer ***/

char (code *fp[3])(void) ; 

/*** Main Calling Function ***/

void main(void) {

   char am ;

   fp[0] = func1 ;     // Point array elements at functions
   fp[1] = func2 ;
   fp[2] = func3 ;

   am = fp[0] ;        // Execute functions
   am = fp[1] ;
   am = fp[2] ;

   if(P1) {            // Control which function is called



      am = execute(func4) ; // Tell execute function which 
                    to run
      }
   else {

      am = execute(func5) ; // Tell execute function which 
                    to run
      }
   }

Resulting Linker Output .M51 File for the dangerous condition.


MS-DOS MCS-51 LINKER / LOCATER  L51 V2.8, INVOKED BY: L51 MAIN.OBJ TO EXEC.ABS

OVERLAY MAP OF MODULE:   EXEC.ABS (MAIN)
                                //overlaid with    

SEGMENT                          DATA-GROUP 
  +_> CALLED SEGMENT          START    LENGTH

?C_C51STARTUP                  
  +_> ?PR?MAIN?MAIN

?PR?MAIN?MAIN                  000EH    0001H
  +_> ?PR?FUNC1?MAIN
  +_> ?PR?FUNC2?MAIN
  +_> ?PR?FUNC3?MAIN
  +_> ?PR?FUNC4?MAIN
  +_> ?PR?_EXECUTE?MAIN
  +_> ?PR?FUNC5?MAIN

?PR?FUNC1?MAIN                 000FH    000BH

?PR?FUNC2?MAIN                 000FH    000BH

?PR?FUNC3?MAIN                 000FH    000BH    //Danger func4's
                                                 //local
?PR?FUNC4?MAIN                 000FH    000BH    //func4's data 
?PR?_EXECUTE?MAIN              000FH    000EH    //execute's, its 
  +_> ?C_LIB_CODE                                //caller!!

?PR?FUNC5?MAIN                 000FH    000BH    //func5's local 
                                                 //data overlaid 
                                                 //with execute's, 
                                                 //its caller!!

RAM Locations Used:

D:0012H         SYMBOL        tex     // execute's locals overlap
D:0013H         SYMBOL        arrex   // func4 and func5's - OK

D:000FH         SYMBOL        y
D:0010H         SYMBOL        arr4

D:000FH         SYMBOL        y5
D:0010H         SYMBOL        arr5

Incidentally, the overlay map shows which functions referred to which other functions. By checking what L51 has found against what you expect, overlay hazards may be spotted.

8.4.2.2 Indirectly called functions solution

Use the overlay command when linking thus

main.obj & to exec.abs & OVERLAY(main ; (func4,func5), _execute ! (func4,func5))

Note: The tilde sign ';' means: "Ignore the reference to func4/5 from main" The '!' means: "Manually generate a reference between intermediate function 'execute' and func4/5 to prevent overlaying of local variables within these functions."

Please make sure you understand exactly how this works!!!

The new linker output is:

MS-DOS MCS-51 LINKER / LOCATER L51 V2.8, INVOKED BY:

L51 MAIN.OBJ TO EXEC.ABS OVERLAY(MAIN ;(FUNC4, FUNC5), _EXECUTE ! (FUNC4, FUNC5))
OVERLAY MAP OF MODULE:   EXEC.ABS (MAIN)

SEGMENT                                 DATA-GROUP 
 +_> CALLED SEGMENT        START       LENGTH
________________________________________________________________

?C_C51STARTUP                  
  +_> ?PR?MAIN?MAIN		-        -        -      -

?PR?MAIN?MAIN                          0024H    0001H    
  +_> ?PR?FUNC1?MAIN            -                        -
  +_> ?PR?FUNC2?MAIN
  +_> ?PR?FUNC3?MAIN
  +_> ?PR?_EXECUTE?MAIN

?PR?FUNC1?MAIN                         0025H    000BH
                                -                        -
?PR?FUNC2?MAIN                         0025H    000BH
                                -                        -
?PR?FUNC3?MAIN                         0025H    000BH
                                -                        -
?PR?_EXECUTE?MAIN                      0025H    000EH
  +_> ?C_LIB_CODE

D:0028H         SYMBOL        tex    // Execute's variables 
                                         no longer 
D:0029H         SYMBOL        arrex  // overlaid with func4/
                                         5's

D:0008H         SYMBOL        y
D:0009H         SYMBOL        arr4

D:0013H         SYMBOL        y5
D:0014H         SYMBOL        arr5

*** WARNING 16: UNCALLED SEGMENT,IGNORED FOR OVERLAY     PROCESS
    SEGMENT: ?PR?FUNC4?MAIN

*** WARNING 16: UNCALLED SEGMENT,IGNORED FOR OVERLAY PROCESS
    SEGMENT: ?PR?FUNC5?MAIN

Note: The WARNING 16's show that func4/5 have been removed from the overlay process to remove the hazard. See section 8.4.2.6 on the "UNCALLED SEGMENT, IGNORED FOR OVERLAY

PROCESS" warning.

8.4.2.3 Function Jump Table Warning

(Non-hazardous)

Here two functions are called an array of function pointers. The array "jump_table" exists in a segment called "?CO?MAIN1, i.e. the constant area assigned to module main. The problem arises that the two message string arguments to the printf 's are also sited here. This leads to a recursive definition of the function start addresses in the jump table.

While this is not in itself dangerous, it prevents the real function references from being established and hence the overlaying process is inhibited.


***********************************************************;
*<<<<<<<<<<<<<Recursive Call To Segment Error>>>>>>>>>>>>>>* 
***********************************************************;
#include <stdio.h>
#include <reg517.h>

void func1(void) {
   
   unsigned char i1 ;
   
   for(i1 = 0 ; i1 < 10 ; i1++) {
 
      printf("THIS IS FUNCTION 1\n") ;  // String stored in 
                                          ?CO?MAIN1 segment
      }
   }

void func2(void) {
   
   unsigned char i2 ;
   
   for(i2 = 0 ; i2 < 10 ; i2++) {

      printf("THIS IS FUNCTION 2\n") ;  // String stored in 
                                          ?CO?MAIN1 segment
      }
   }

code void(*jump_table[])()={func1,func2}; //Jump table to 
                                            functions,
                                          // table stored in 
                                            ?CO?MAIN1
                                          // segment.
/*** Calling Function ***/


main() {

   (*jump_table[P1 & 0x01])() ;   // Call function via jump 
                                         table in ?CO?MAIN1
    }
    ^^^^^^^^^^^^^^^^^^^^^^^ End of Module

The resulting link output is:

Note: No reference exists between main and func1/2 so the overlay process cannot occur, resulting in wasted RAM.


OVERLAY MAP OF MODULE:   MAIN1 (MAIN1)

MCS-51 LINKER / LOCATER  L51 V2.8 
DATE  04/08/92   PAGE    2
SEGMENT                    BIT-GROUP          DATA-GROUP 
  +_> CALLED SEGMENT   START    LENGTH     START    LENGTH
________________________________________________________________

?C_C51STARTUP            -        -          -         -
  +_> ?PR?MAIN?MAIN1

?PR?MAIN?MAIN1           -        -          -         -    
  +_> ?CO?MAIN1
  +_> ?C_LIB_CODE

?CO?MAIN1                -        -          -         -      
  +_> ?PR?FUNC1?MAIN1
  +_> ?PR?FUNC2?MAIN1

?PR?FUNC1?MAIN1          -        -        0008H    0001H
  +_> ?PR?PRINTF?PRINTF


?PR?PRINTF?PRINTF      0020H.0  0001H.1    0009H    0014H
  +_> ?C_LIB_CODE
  +_> ?PR?PUTCHAR?PUTCHAR

?PR?FUNC2?MAIN1         -         -       0008H    0001H
  +_> ?PR?PRINTF?PRINTF

*** WARNING 13: RECURSIVE CALL TO SEGMENT
    SEGMENT: ?CO?MAIN1
    CALLER:  ?PR?FUNC1?MAIN1

*** WARNING 13: RECURSIVE CALL TO SEGMENT
    SEGMENT: ?CO?MAIN1
    CALLER:  ?PR?FUNC2?MAIN1

8.4.2.4 Function Jump Table Warning Solution

The solution is to use the OVERLAY command when linking thus


main1.obj & 
to main1.abs & 
OVERLAY(?CO?MAIN1 ~ (func1,func2), main ! (func1,func2))

This deletes the reference to func1 & 2 from the ?CO?MAIN1 segment and inserts the true reference from main to func1 & func2.

The linker output is now thus:


OVERLAY MAP OF MODULE:   MAIN1.ABS (MAIN1)

SEGMENT                   BIT-GROUP          DATA-GROUP 
  +_> CALLED SEGMENT    START    LENGTH     START    LENGTH
________________________________________________________________

?C_C51STARTUP             -         -          -        -      
  +_> ?PR?MAIN?MAIN1

?PR?MAIN?MAIN1            -         -          -        -  
  +_> ?CO?MAIN1
  +_> ?C_LIB_CODE
  +_> ?PR?FUNC1?MAIN1
  +_> ?PR?FUNC2?MAIN1

?PR?FUNC1?MAIN1           -         -        0008H    0001H
  +_> ?CO?MAIN1
  +_> ?PR?PRINTF?PRINTF

?PR?PRINTF?PRINTF        0020H.0  0001H.1    0009H    0014H
  +_> ?C_LIB_CODE
  +_> ?PR?PUTCHAR?PUTCHAR

?PR?FUNC2?MAIN1           -         -        0008H    0001H
  +_> ?CO?MAIN1
  +_> ?PR?PRINTF?PRINTF

8.4.2.5 Multiple Call To Segment Warning

(Hazardous)

This warning generally occurs when a function is called from both the background and an interrupt. This means that potentially the interrupt may call the function whilst it is still running, as a result of a background level call. The result could be the over-writing of the local data in the background. The fact that the offending function is also overlaid with other background functions makes the chances of failure very high. The simplest solution is to declare the function as REENTRANT so that the compiler will generate a local stack for parameters and variables. Thus on each call to the function, a new set of parameters and local variables are created without destroying any existing ones from the current call.

Unfortunately this significantly increases the run time and code produced. Another possibility is to make a second and renamed version of the function, one for background use and one for interrupt. This is somewhat wasteful and presents a maintenance problem, as you now have effectively two versions of the same piece of code.

In many cases the situation is not a problem, as the user may have ensured that the reentrant use could never occur, but is left with the linker warning. However this must be viewed as dangerous, particularly if more than one programmer is involved.


#include <stdio.h>
#include <reg517.h>

void func1(void) {
   
   unsigned char i1,a1[15] ;
   
   for(i1 = 0 ; i1 < 10 ; i1++) {
 
      a1[i1] = i1 ; 
      }
   }

void func2(void) {
   
   unsigned char i2,a2[15] ;
   
   for(i2 = 0 ; i2 < 10 ; i2++) {
 

      a2[15] = i2 ;
      }
   }

main() {
   func1() ;
   func2() ;
   }

void timer0_int(void) interrupt 1 {
   func1() ;
   } ^^^^^^^^^^^^^^^^^^^^^^^ End of Module

This produces the linker map:

OVERLAY MAP OF MODULE:   MAIN2 (MAIN2)
SEGMENT                          DATA-GROUP 
  +_> CALLED SEGMENT          START    LENGTH

?PR?TIMER0_INT?MAIN2          
  +_> ?PR?FUNC1?MAIN2

?PR?FUNC1?MAIN2               0017H    000FH

?C_C51STARTUP                  
  +_> ?PR?MAIN?MAIN2

?PR?MAIN?MAIN2                
  +_> ?PR?FUNC1?MAIN2
  +_> ?PR?FUNC2?MAIN2

?PR?FUNC2?MAIN2               0017H    000FH

D:0007H         SYMBOL        i1  // Danger!
D:0017H         SYMBOL        a1

D:0007H         SYMBOL        i2
D:0017H         SYMBOL        a2

*** WARNING 15: MULTIPLE CALL TO SEGMENT
    SEGMENT: ?PR?FUNC1?MAIN2
    CALLER1: ?PR?TIMER0_INT?MAIN2
    CALLER2: ?C_C51STARTUP

8.4.2.6 Multiple Call To Segment Solution

The solution is to

(i) Declare func1 as REENTRANT thus:

void func1(void) reentrant {  }

(ii) Use OVERLAY linker option thus:


main2.obj & 
to main2.abs & 
OVERLAY(main ~ func1,timer0_int ~ func1)

to break connection between main and func1 and timer0_int and func1.

OVERLAY MAP OF MODULE:   MAIN2.ABS (MAIN2)

SEGMENT                          DATA-GROUP 
  +_> CALLED SEGMENT          START    LENGTH
___________________________________________________

?C_C51STARTUP                   -         -
  +_> ?PR?MAIN?MAIN2        

?PR?MAIN?MAIN2                  -         - 
  +_> ?PR?FUNC2?MAIN2

?PR?FUNC2?MAIN2               0017H    000FH

*** WARNING 16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS
    SEGMENT: ?PR?FUNC1?MAIN2

This means that the safe overlaying of func1 with other background functions will not occur. Removing the link only with the interrupt would solve this:


main2.obj & 
to main2.abs & 
OVERLAY(timer0_int ~ func1)

Another route would be to disable all overlaying but this is likely to eat up large amounts of RAM very quickly and is thus a poor solution.

main2.obj & to main2.abs & NOOVERLAY

With the MULTIPLE CALL TO SEGMENT WARNING the only really "safe" solution is to declare func1 as REENTRANT, with the duplicate function a good second. The danger of using the OVERLAY command is that a less experienced programmer new to the system might not realise that the interrupt is restricted as to when it can call the function and hence system quality is degraded.

8.4.3 Overlaying Public Variables

All the preceding examples deal with the overlaying of locals and parameters at a function level. A case occurred recently in which the program was split into two distinct halves; the divide taking place very early on. To all intents a_nd purposes the 8051 was able to run one of two completely different application programs, based on some user input during initialisation.

Each program half had a large number of public variables, some of which were known to both sides but the majority of which were local to one side only. This is almost multitasking.

This type of program structure really needs a new storage class like "GLOBAL", with public meaning available to a certain number of modules only. GLOBAL would then be available to all modules. The new C166 supports this type of task-based variable scope. Unfortunately C51 does not, so a fix is required.

The linker's OVERLAY command does not help, as it only controls the overlaying of local and parameter data. One possible solution uses special modules to declare the publics. Module1 declares the publics for program (task1); Module2 declares the publics for program2 (task2). Finally, Module3 declares the publics which are available to both sides.

The trick then is to use the linker to fix the data segments on Module1 and Module2 at the same physical address, whilst allowing Module3's variables to be placed automatically by the linker.

This solution uses three special modules for declaring the publics:


/* Example of creating two sets of public data */
/*in same memory space */

extern void main1(void) ; 
extern void main0(void) ;

/* Main module where system splits into two parts */

void main(void) {
   bit flag ;

   if(flag) {
      main0() ;   // Branch 0
      }
   else {
      main1() ;   // Branch 1
      }
   } ^^^^^^^^^^^^^^^^^^^^^^^ End of Module

/* Module that declares publics for branch 2 */

/* Publics for branch 2 */

unsigned char x2,y2 ; 
unsigned int z2 ; 
char a2[0x30] ;

/* A variable which is accessible from both branches */

extern int common ;  

^^^^^^^^^^^^^^^^^^^^^^^ End of Module

void main0(void) {

   unsigned char c0 ; /* Local - gets overlaid with c1 in*/
                /*other branch */
   x2 = 0x80 ;
   y2 = x2 ;

   c0 = y2 ;

   z2 = x2*y2 ;

   a2[2] = x2 ;

   common = z2 ;

   }

^^^^^^^^^^^^^^^^^^^^^^^ End of Module



/* Module that declares publics for branch 1 */

/* Publics for branch 1 */

unsigned char x1,y1 ; 
unsigned int z1 ; 
char a1[0x30] ;

/* A variable which is accessible from both branches */

extern int common ;

void main1(void) {

   char c1 ;

   x1 = 0x80 ;
   y1 = x1 ;

   c1 = y1 ;

   z1 = x1*y1 ;
   a1[2] = x1 ;

   common = z1 ;
 
   }
^^^^^^^^^^^^^^^^^^^^^^^ End of Module

/* Module that declares variables that both */
/*branches can access */

int common ; /* A variable common to both branches */

^^^^^^^^^^^^^^^^^^^^^^^ End of Module

/* Linker Input */

l51 t.obj,t1.obj,t2.obj,com.obj to t.abs
DATA(?DT?T1(20H),?DT?T2(20H))

The choice of "20H" for the location places the combined segments just above the register banks.

The main problem with this approach is that a DATA overlay warning is produced. This is not dangerous but is obviously undesirable.


[Back] [Top] [Next]