?? c519.txt
字號:
發(fā)信人: reflection (似水流年), 信區(qū): EEtechnology
標(biāo) 題: C51 Primer (8) Linking Issues and Stack Placement
發(fā)信站: 南京大學(xué)小百合站 (Wed Nov 24 12:01:52 1999), 轉(zhuǎn)信
8 Linking Issues And Stack Placement
This causes some confusion, especially to those used to other compiler syste
ms.
8.1 Basic Use Of L51 Linker
The various modules of a C program are combined by a linker. After compilati
on no actual addresses are assigned to each line of code produced, only an o
ffset is generated from the start of the module. Obviously before the code c
an be executed each module must be tied to a unique address in the code memo
ry. This is done by the linker.
L51, in the case of Keil (RL51 for Intel), is a utility which assigns absolu
te addresses to the compiled code. It also searches library files for the ac
tual 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 com
bined. Any calls to library functions in any of these files results in the l
ibrary, C51L.lib, being searched for the appropriate code.
The target addresses (or offsets) for any JMPs or CALLs are calculated and i
nserted after the relevant opcodes.
When all five .obj files have been combined, they are placed into another fi
le called EXEC.ABS, the ABS implying that this is absolute code that could a
ctually be executed by an 8051 cpu. In addition, a "map" file called EXEC.M5
1 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 lin
ked 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 (E
prom) 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 a
nd 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 giv
e maximum stack space. Thus after locating all the sfr, compiled stack and d
ata 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-addressa
ble 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 addressab
le RAM. C51, when in the SMALL model, can use this for variables, arrays, st
ructures 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 add
ressed, be used as additional storage. The main use of this area is really a
s stack. Data in this area is addressed by the MOV A,@Ri instruction. As onl
y indirect addressing can be used, there can be some loss of efficiency as t
he Ri register must be loaded with the required 8 bit address before any acc
ess can be made.
Left to its own devices C51 will not use this area other than for stack. Unu
sually, the 8051 stack grows up through RAM, so the linker will place the ST
ACK area at the top of the area taken up with variables, parameter passing s
egments 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 declari
ng some variables as "idata" and using "RAMSIZE(256)" when linking.
Such is human nature that most people will not think of using idata until th
e lower 128 bytes actually overflows and a panic-driven search begins for mo
re 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 variab
le 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 a
bove these new idata objects.
To summarise, with the 8052 if you are hitting the 128 byte ceiling of the d
irectly addressable space, the moving of arrays and pointer addressable obje
cts can free-up large amounts of valuable directly addressable RAM very easi
ly.
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 a
n 8051 is the OVERLAY function. This is a mechanism whereby different progra
m variables make use of the same RAM location(s). This possibility arises wh
en automatic local variables are declared. These by definition only have sig
nificance during the execution of the function within which they were define
d. Once the function is exited the area of RAM used by them is no longer req
uired. 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 mem
ory reserved for its locals and parameters. Within the confines of an 8051 t
he 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 b
iggest 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 cal
led "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 l
ocal data but one particular one needs 10, the DATA_GROUP will be 10 bytes l
ong.
Using the registers as a location for temporary data means that a large numb
er 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 t
heir 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 i
ts 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 canno
t 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 attache
d 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 occu
r at any time, they would overwrite the local data currently generated by wh
ichever background (or lower priority interrupt) function was running, were
they also to use the DATA_GROUP. To cope with this, C51 identifies the inter
rupt 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 execu
ting simultaneously may have their local data overlaid. Re-entrant functions
are an extension of this in that a single function may be called simultaneo
usly from two different places.
In 99% of cases the overlay function works perfectly but there are some case
s where it can give unexpected results.
These are basically:
Indirectly-called functions using function pointers
Functions called from jump tables of functions
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 th
e program, it cannot establish a direct link between execute and func4/5 bec
ause the function pointer received as a parameter breaks the chain of refere
nces - this function pointer is undefined at link time. Thus L51 overlays th
e 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 exe
cute. This is clearly VERY dangerous, especially as the overwriting may not
be immediately obvious - it may only appear under abnormal operating conditi
ons 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.A
BS
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 h
azards 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,fun
c5))
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, FU
NC5))
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
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -