Showing changes from revision #5 to #6:
Added | Removed | Changed
The “Hello, world!” example from the first part will have given you a basic idea of the structure of ObjAsm source files. But to get a full understanding, you’ll need to take a closer look.
; This is a comment
Comments must start with a semicolon, and will run until the end of the line. Comments can appear on any line.
AREA helloworld, CODE, READONLY
Every assembler statement, label definition, or block of data must be located within an area. In a way, an area is similar to the square brackets that enclose blocks of assembler in BASIC. Your program can contain multiple areas, and the order of the areas in the source code does not necessarily have to match the order of the areas in the final binary.
Each area has a name. The primary purpose of the name is to determine the order in which the areas will appear in the final binary (when comparing two name strings, the area with the name which appears first will appear first within the binary). Area names can consist of any sequence of printable, non-whitespace ASCII characters, therefore an area named !
will always appear first (although you may need to escape the name using |
, i.e. |!|
).
For each area name, the linker will generate a couple of special symbols which provide the start and end addresses of the area within the image. These take the form <areaname>$$Base
and <areaname>$$Limit
. The C runtime makes use of this functionality to determine how much zero-initialised workspace the program requires, so that it can grow the application slot to the appropriate size and then zero the memory.
If you have multiple areas with the same name, they will be merged together into one area in the final binary. However if any of the area attributes conflict, an error will be produced.
Each area also has a series of attributes associated with it. Some attributes will affect the behaviour of the assembler, while others will affect the linker. The most important attributes are as follows:
CODE
, DATA
– These mark the area as containing either code or data. Primarily this affects the behaviour of debugging and disassembly tools.READONLY
– As the name implies, this indicates that the area is intended to be read-only.; ... code here ... END
Every source file must end with an END
directive. Once the END directive is reached, processing of that file will stop – anything placed after the END is ignored.
some_label
To define a label, simply place the label name at the start of the line, with no preceeding whitespace.
You can also place an instruction on the same line as the label, e.g.
memset MOV R3,R0 loop SUBS R2,R2,#1 STRGEB R1,[R3],#1 BGT loop MOV PC,LR
Local labels are also supported. These are labels which start with a number as the first character. For example, some simple memset and memcpy routines could be written as follows:
memset ROUT MOV R3,R0 10 SUBS R2,R2,#1 STRGEB R1,[R3],#1 BGT %BT10 MOV PC,LR memcpy ROUT MOV R3,R0 10 SUBS R2,R2,#1 LDRGEB R12,[R1],#1 STRGEB R12,[R3],#1 BGT %BT10 MOV PC,LR
If you compare the memset routine to the earlier example you’ll see three key differences:
loop
label has been replaced with 10
, a local label%BT10
to refer to the label. The full syntax of local label references is given below, but for now just know that this means “scan backwards for label 10”.ROUT
directive has been added at the start of the routine.ROUT
is the key to allowing local variables to safely be used. When the assembler tries to resolve the %BT10
reference, it will start scanning backwards (i.e. to preceding source lines) looking for the 10
. If it hits a ROUT
directive it will stop its search. Therefore ROUT
acts as a way of defining the scope of local variables. Without it, you could accidentally reference a local variable defined by another routine and have a nasty crash bug when you run your code.
Note that ObjAsm is perfectly happy with allowing you to define the same local label multiple times within the same ROUT block – when it scans forwards/backwards for the label it simply stops at the first definition it sees. Also note that ROUT does not need to be placed directly on a label, like most other directives you can also place it on a line of its own.
The syntax of local label references is as follows:
%XYnnn
B
to scan backwards, F
for forwards, or omitted to scan both forwards and backwards (selecting the closest definition – potentially dangerous if you define the same label multiple times).A
will search through all macro levels, T
will only look at the current macro level, and omitting the flag will cause the search to look from the current macro level up to the top level.Best practice is to include both the X and Y flags whenever possible, both to reduce the risk of bugs, and to make the code quicker and easier to read.
Note that you can also include a “routine name” in the label reference, but in practice this feature is rarely used.
OS_Exit * &11
Like labels, constant definitions must be located at the start of a line. *
or EQU
can be used to separate the name from the value, although in practice *
is the most commonly used.
The right hand side of the constant can be any expression, e.g. you can have one constant which refers to another:
X_Bit * &20000 OS_Exit * &11 XOS_Exit * OS_Exit + X_Bit