// main.c
extern long blah(char *);
int main() {
long a = blah("2a");
}// main.s
idnt "main.c"
opt o+,ol+,op+,oc+,ot+,oj+,ob+,om+
section "CODE",code
public _main
cnop 0,4
_main
subq.w #4,a7
movem.l l4,-(a7)
pea l3
jsr _blah
move.l d0,(4+l6,a7)
moveq #0,d0
addq.w #4,a7
l1
l4 reg
l6 equ 0
addq.w #4,a7
rts
cnop 0,4
l3
dc.b 50
dc.b 97
dc.b 0
public _blah@djgruby, post #1
@djgruby, post #1
In that listing, `reg` is NOT a 68000 CPU instruction. It is an assembler directive used to define a MOVEM register mask constant. What it is doing here: You have: ``` movem.l l4,-(a7) ... l4 reg ``` So the label `l4` is being defined as a register-list value (a bitmask) that MOVEM can use. Many 68k assemblers (and C compilers that emit assembly) support a `REG` directive to build the 16-bit MOVEM mask: ``` bits 0–7 -> D0–D7 bits 8–15 -> A0–A7 ``` Example (what it could look like): ``` l4 reg d2-d3/a2-a3 ; l4 becomes the corresponding MOVEM mask ``` Why is it empty (`l4 reg` with no list)? In your snippet it is blank, so it typically means: ``` no registers need saving, so the mask is 0 ``` Compilers often still emit the movem + reg pattern as a template, even when the set ends up empty. So effectively, in this function, it is saying: ``` "Here is the register-save mask for this function (and it happens to be empty)." ``` If you later saw an epilogue like: ``` movem.l (a7)+,l4 ``` it would use the same mask to restore the saved registers (though your snippet does not show that restore).
@ppill, post #3
@djgruby, post #4
Good catch to question it - but in this specific snippet, no, it would not cause a pointer or stack misalignment because `l4 reg` is effectively an empty MOVEM mask. What happens to A7 (the stack pointer) in your code: Let us track the stack pointer changes step by step. 1. Prologue reserve: subq.w #4,a7 A7 = A7 - 4 2. Save registers: movem.l l4,-(a7) This would push the registers listed in `l4`. But since `l4 reg` has no register list, the mask is 0. That means it pushes nothing. Net effect: A7 unchanged. 3. Push argument: pea l3 Pushes 4 bytes. A7 = A7 - 4 4. Call: jsr _blah The CPU pushes the return address (4 bytes). During the call: A7 = A7 - 4 When `_blah` executes RTS, the return address is popped, so A7 returns to the value it had just before JSR. After return: A7 = original - 4 - 4 5. Clean up argument: addq.w #4,a7 Pops the argument pushed by PEA. A7 = original - 4 6. Epilogue: addq.w #4,a7 Undoes the initial stack reservation. A7 = original value So the stack is balanced. When would it be a problem? It would be a problem if `l4` were non-empty (for example saving d2/a2) and you did not restore it with something like: movem.l (a7)+,l4 Because `movem.l l4,-(a7)` would decrement A7 by 4 times the number of registers saved. If you never increment A7 by the same amount, you would return with A7 incorrect and RTS would jump to the wrong address. Even with an empty mask, some assemblers may still encode MOVEM, but it effectively moves zero registers and has no effect on A7. Bottom line: in your snippet, missing the restore does not misalign anything as long as `l4` really resolves to mask 0. If `l4` ever includes registers, then yes, it would break the stack unless restored or A7 adjusted by the same amount.
@djgruby, post #4
subq.w #4,a7
addq.w #4,a7
link.w a5,#-16
unlk a5
DAS handles the following directives:
DC declare data
DS declare space / align
SECTION declare a section. Sections may be repeated to flip
back and forth between them. A third argument
may contain a value to be ORd with the hunk
type field, usually used to specify special
hunk flags (i.e. hunk to chip memory, etc...)
XREF import a label
XDEF export a label
EQU declare a constant (must be a numerical constant)
REG declare zero or more registers in register list
...
* MOVEM's using 'reg' labels are optimized to either a MOVE or by
removing the MOVEM entirely (reg labels that specify no registers).@ppill, post #5
movem.l l4,-(a7) l4 reg
@djgruby, post #7
<symbol> reg <reglist>
Defines a new symbol named <symbol> and assign the register list <reglist> to
it. Registers in a list must be separated by a slash (/) and ranges or registers
can be defined by using a hyphen (-). Examples for valid register lists are:
d0-d7/a0-a6, d3-6/a0/a1/a4-5.