Discussion:
JWASM stack frame when using cdecl / C
(too old to reply)
Binarus
2013-03-04 16:00:42 UTC
Permalink
Hi all,

I have a 16-bit (DOS) assembler module which I compile using JWasm and the following command line:

jwasm -5p -e20 -FPi87 -fp3 -Gd -W4 -WX -zcm -omf -Fo=bla.obj bla.asm

Within the source file, I have PROC declarations / definitions like the following:

PUBLIC C Foo


FOO PROC FAR C

<code goes here>

FOO ENDP

Now, JWasm compiles a "half" of a stack frame automatically with the following result:

FOO PROC FAR C

push bp
mov bp, sp

<code goes here>

FOO ENDP

That means that it generates the stack entry frame, but not the stack leaving frame.

This is not really a problem because I can add the missing "pop bp" at the end of every PROC manually. But I'm feeling a bit uncomfortable doing so, considering that I might need to compile the code with other assemblers in the future, and I'm strongly interested in knowing what I am doing wrong.

By the way, there is no .MODEL directive in the code.

Any comments?

Thank you very much,

Binarus
Uwe Schmelich
2013-03-04 17:47:35 UTC
Permalink
Post by Binarus
Hi all,
I have a 16-bit (DOS) assembler module which I compile using JWasm and the
jwasm -5p -e20 -FPi87 -fp3 -Gd -W4 -WX -zcm -omf -Fo=bla.obj bla.asm
PUBLIC C Foo
FOO PROC FAR C
<code goes here>
FOO ENDP
FOO PROC FAR C
push bp
mov bp, sp
<code goes here>
FOO ENDP
That means that it generates the stack entry frame, but not the stack leaving frame.
This is not really a problem because I can add the missing "pop bp" at the
end of every PROC manually. But I'm feeling a bit uncomfortable doing so,
considering that I might need to compile the code with other assemblers in
the future, and I'm strongly interested in knowing what I am doing wrong.
By the way, there is no .MODEL directive in the code.
Any comments?
Thank you very much,
Binarus
Assuming that you have a 'ret' in your code I wasn't able to recreate this
behaviour. Could you please give a fully compilable example exhibiting
this?
Binarus
2013-03-05 12:02:56 UTC
Permalink
Post by Uwe Schmelich
Assuming that you have a 'ret' in your code I wasn't able to recreate this
behaviour. Could you please give a fully compilable example exhibiting
this?
Uwe, thanks for helping. Here is an example (of course, it does nothing meaningful, but shows the problem).

;***********BEGIN OF CODE

.586p

;----------------------------------------
;----------------------------------------
;----------------------------------------
test_TEXT SEGMENT WORD PUBLIC USE16 'CODE'
;----------------------------------------

PUBLIC C E820_FetchEntry


;---------------------------------
;---------------------------------
E820_FetchEntry PROC FAR C,
pul_BiosBlock: PTR FAR DWORD,
pv_Buffer: PTR FAR BYTE,
pui_Carry: PTR FAR WORD,
pul_Signature: PTR FAR DWORD,
pul_BytesWritten: PTR FAR DWORD
;----------------------------

PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ES

MOV EAX, [pul_BiosBlock]
LES DI, [pv_Buffer]
MOV EBX, [pui_Carry]
MOV ECX, [pul_Signature]
MOV EDX, [pul_BytesWritten]

POP ES
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX

RETF

;--------------------
E820_FetchEntry_ ENDP
;--------------------
;--------------------


;------------
test_TEXT ENDS
;------------
;------------
;------------


END

;********END OF CODE

To reproduce the problem, pleas save the code above in a file called test.asm. Then compile the code using the following command line:

jwasm -5p -e20 -FPi87 -fp3 -Gd -W4 -WX -zcm -omf test.asm

You now should have an object file called test.obj. Now let's disassemble the object file:

wdis test.obj

The result is:

**********************BEGIN OF WDIS OUTPUT

Module: test.asm

Segment: TEST_TEXT WORD USE16 0000002D bytes
0000 _E820_FetchEntry:
0000 55 push bp
0001 8B EC mov bp,sp
0003 66 50 push eax
0005 66 53 push ebx
0007 66 51 push ecx
0009 66 52 push edx
000B 66 57 push edi
000D 06 push es
000E 66 8B 46 06 mov eax,dword ptr 0x6[bp]
0012 C4 7E 0A les di,dword ptr 0xa[bp]
0015 66 8B 5E 0E mov ebx,dword ptr 0xe[bp]
0019 66 8B 4E 12 mov ecx,dword ptr 0x12[bp]
001D 66 8B 56 16 mov edx,dword ptr 0x16[bp]
0021 07 pop es
0022 66 5F pop edi
0024 66 5A pop edx
0026 66 59 pop ecx
0028 66 5B pop ebx
002A 66 58 pop eax
002C CB retf

Routine Size: 45 bytes, Routine Base: TEST_TEXT + 0000

No disassembly errors

**********************END OF WDIS OUTPUT

The first two instructions are a typical __cdecl stack frame and got compiled in automatically, hopefully due to the "C" qualifier I have used for declaring and defining the procedure. That's what I wanted and expected.

But what's the reason for no "pop bp" being at the end of the procedure? Without it, the code program will definitely be continued at the wrong place after the retf.

Thank you very much,

Binarus
Uwe Schmelich
2013-03-05 15:30:56 UTC
Permalink
Post by Binarus
Post by Uwe Schmelich
Assuming that you have a 'ret' in your code I wasn't able to recreate
this behaviour. Could you please give a fully compilable example
exhibiting this?
Uwe, thanks for helping. Here is an example (of course, it does nothing
meaningful, but shows the problem).
;***********BEGIN OF CODE
.586p
;----------------------------------------
;----------------------------------------
;----------------------------------------
test_TEXT SEGMENT WORD PUBLIC USE16 'CODE'
;----------------------------------------
PUBLIC C E820_FetchEntry
;---------------------------------
;---------------------------------
E820_FetchEntry PROC FAR C,
pul_BiosBlock: PTR FAR DWORD,
pv_Buffer: PTR FAR BYTE,
pui_Carry: PTR FAR WORD,
pul_Signature: PTR FAR DWORD,
pul_BytesWritten: PTR FAR DWORD
;----------------------------
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ES
MOV EAX, [pul_BiosBlock]
LES DI, [pv_Buffer]
MOV EBX, [pui_Carry]
MOV ECX, [pul_Signature]
MOV EDX, [pul_BytesWritten]
POP ES
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
RETF
;--------------------
E820_FetchEntry_ ENDP
;--------------------
;--------------------
;------------
test_TEXT ENDS
;------------
;------------
;------------
END
;********END OF CODE
To reproduce the problem, pleas save the code above in a file called
jwasm -5p -e20 -FPi87 -fp3 -Gd -W4 -WX -zcm -omf test.asm
wdis test.obj
**********************BEGIN OF WDIS OUTPUT
Module: test.asm
Segment: TEST_TEXT WORD USE16 0000002D bytes
0000 55 push bp
0001 8B EC mov bp,sp
0003 66 50 push eax
0005 66 53 push ebx
0007 66 51 push ecx
0009 66 52 push edx
000B 66 57 push edi
000D 06 push es
000E 66 8B 46 06 mov eax,dword ptr 0x6[bp]
0012 C4 7E 0A les di,dword ptr 0xa[bp]
0015 66 8B 5E 0E mov ebx,dword ptr 0xe[bp]
0019 66 8B 4E 12 mov ecx,dword ptr 0x12[bp]
001D 66 8B 56 16 mov edx,dword ptr 0x16[bp]
0021 07 pop es
0022 66 5F pop edi
0024 66 5A pop edx
0026 66 59 pop ecx
0028 66 5B pop ebx
002A 66 58 pop eax
002C CB retf
Routine Size: 45 bytes, Routine Base: TEST_TEXT + 0000
No disassembly errors
**********************END OF WDIS OUTPUT
The first two instructions are a typical __cdecl stack frame and got
compiled in automatically, hopefully due to the "C" qualifier I have used
for declaring and defining the procedure. That's what I wanted and
expected.
But what's the reason for no "pop bp" being at the end of the procedure?
Without it, the code program will definitely be continued at the wrong
place after the retf.
Thank you very much,
Binarus
Ok, I was able to reproduce it. The behaviour is the same with jwasm and
masm10, so at least jwasm is compatible with masm here. If you use 'ret'
instead of 'retf' then a 'pop bp' is generated by jwasm and a 'leave' by
masm. If you want the 'leave' in jwasm too, you have to use the additional
parameter -Zg.

Uwe
Binarus
2013-03-05 16:18:49 UTC
Permalink
Post by Uwe Schmelich
Post by Binarus
Uwe, thanks for helping. Here is an example (of course, it does nothing
meaningful, but shows the problem).
;***********BEGIN OF CODE
.586p
;----------------------------------------
;----------------------------------------
;----------------------------------------
test_TEXT SEGMENT WORD PUBLIC USE16 'CODE'
;----------------------------------------
PUBLIC C E820_FetchEntry
;---------------------------------
;---------------------------------
E820_FetchEntry PROC FAR C,
pul_BiosBlock: PTR FAR DWORD,
pv_Buffer: PTR FAR BYTE,
pui_Carry: PTR FAR WORD,
pul_Signature: PTR FAR DWORD,
pul_BytesWritten: PTR FAR DWORD
;----------------------------
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ES
MOV EAX, [pul_BiosBlock]
LES DI, [pv_Buffer]
MOV EBX, [pui_Carry]
MOV ECX, [pul_Signature]
MOV EDX, [pul_BytesWritten]
POP ES
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
RETF
;--------------------
E820_FetchEntry_ ENDP
;--------------------
;--------------------
;------------
test_TEXT ENDS
;------------
;------------
;------------
END
;********END OF CODE
To reproduce the problem, pleas save the code above in a file called
jwasm -5p -e20 -FPi87 -fp3 -Gd -W4 -WX -zcm -omf test.asm
You now should have an object file called test.obj. Now let's disassemble
wdis test.obj
**********************BEGIN OF WDIS OUTPUT
Module: test.asm
Segment: TEST_TEXT WORD USE16 0000002D bytes
0000 55 push bp
0001 8B EC mov bp,sp
0003 66 50 push eax
0005 66 53 push ebx
0007 66 51 push ecx
0009 66 52 push edx
000B 66 57 push edi
000D 06 push es
000E 66 8B 46 06 mov eax,dword ptr 0x6[bp]
0012 C4 7E 0A les di,dword ptr 0xa[bp]
0015 66 8B 5E 0E mov ebx,dword ptr 0xe[bp]
0019 66 8B 4E 12 mov ecx,dword ptr 0x12[bp]
001D 66 8B 56 16 mov edx,dword ptr 0x16[bp]
0021 07 pop es
0022 66 5F pop edi
0024 66 5A pop edx
0026 66 59 pop ecx
0028 66 5B pop ebx
002A 66 58 pop eax
002C CB retf
Routine Size: 45 bytes, Routine Base: TEST_TEXT + 0000
No disassembly errors
**********************END OF WDIS OUTPUT
The first two instructions are a typical __cdecl stack frame and got
compiled in automatically, hopefully due to the "C" qualifier I have used
for declaring and defining the procedure. That's what I wanted and
expected.
But what's the reason for no "pop bp" being at the end of the procedure?
Without it, the code program will definitely be continued at the wrong
place after the retf.
Thank you very much,
Binarus
Ok, I was able to reproduce it. The behaviour is the same with jwasm and
masm10, so at least jwasm is compatible with masm here. If you use 'ret'
instead of 'retf' then a 'pop bp' is generated by jwasm and a 'leave' by
masm. If you want the 'leave' in jwasm too, you have to use the additional
parameter -Zg.
Uwe
Uwe, thank you very much.

First of all, I can confirm that if I use ret instead of retf the "pop bp" at the end of the PROC is generated automatically. I don't need the leave, at least in most cases, since PUSHs and POPs are usually balanced in my assembler code.

Besides that, I think that JWasm's behavior (as well as MASM's) is buggy. Let's look at the possible options a poor 16-bit assembler programmer has:

1) Consequently use ret instead of retf. IMHO, this is bad style, very hard to understand by others and quite dangerous. As soon as you are trying to compile that code using other assemblers (outside the MASM sphere), probably the opcode for ret (C3) will be inserted at the end of the PROC instead of retf (CB), meaning that the code will crash.

2) Keep using retf and manually add the pop bp at the end of the PROC. This is as bad as 1) for the same reason: Another assembler (if behaving well) will insert the stack frame at the beginning *and* the end of the PROC, and then you are ending up with the pop bp doubled at the end, once again meaning that the code will crash.

3) Use -Zg. But what if we don't need the implicit MOV SP, BP which is part of LEAVE?

Well, probably we could discuss for a long time which of the three alternatives is the best one, or which one is acceptable.

But I think that automatically inserting operations which leave the stack *unbalanced* in every case is a severe bug that must be avoided under all circumstances.

So may I hope that JWasm gets changed to avoid that bug? - Well, during thinking about it, that would probably mean that the compatibility to MASM would be broken, but perhaps we could introduce a new command line switch which allows the user to choose between the buggy MASM behavior and a correct behavior?

Thank you very much!

Regards,

Binarus
japheth
2013-03-05 16:43:33 UTC
Permalink
Post by Binarus
So may I hope that JWasm gets changed to avoid that bug?
No. This isn't a bug, the behavior is documented and intentional - if you code
RETN or RETF, no epilogue is generated. Btw, it's not just jwasm and masm that
behave this way, but also wasm and tasm.
Tomasz Kępczyński
2013-03-07 08:32:19 UTC
Permalink
Post by japheth
Post by Binarus
So may I hope that JWasm gets changed to avoid that bug?
No. This isn't a bug, the behavior is documented and intentional - if
you code RETN or RETF, no epilogue is generated. Btw, it's not just
jwasm and masm that behave this way, but also wasm and tasm.
And there is good reason for that. Sometimes you need to just push some
address on the stack and want to jump there without clearing up stack
frame. RETN/RETF allow you to do that.

Just treat RETN/RETF (possibly with number of bytes to pop from stack)
as instruction mnemonic and RET as a macro which returns from PROC.

Tomek
Binarus
2013-03-07 12:55:57 UTC
Permalink
Post by japheth
Post by Binarus
So may I hope that JWasm gets changed to avoid that bug?
No. This isn't a bug, the behavior is documented and intentional - if
you code RETN or RETF, no epilogue is generated. Btw, it's not just
jwasm and masm that behave this way, but also wasm and tasm.
And there is good reason for that. Sometimes you need to just push some address on the stack and want to jump there without clearing up stack frame. [...]
But this also could be done without inserting unbalanced stack frames.

If the programmer wants to handle the stack by doing some extras as you have mentioned, the programmer should tell the assembler to not insert any code automatically (neither prologue nor epilogue).

If the programmer wants the assembler to handle the stack frame, the assembler should do so in a balanced way (i.e. pop at end what has been pushed at the beginning). It is quite reasonable to expect that code which is generated automatically does not screw up the stack pointer.

But I now have learned that such behavior is expected, so I will accommodate myself.
Just treat RETN/RETF (possibly with number of bytes to pop from stack) as instruction mnemonic and RET as a macro which returns from PROC.
That's an interesting point of view. So RET should be a macro which happens to have the name of an instruction? Hmmm ...

As we have seen, the epilogue will be generated if RET is used instead of RETF. Following your logic, no epilogue must be generated if RETN is used; I will test this and see what happens (if the assembler accepts RETN at all - the PROCs are all FAR).

Thanks for helping!

Regards,

Binarus
Tomasz Kępczyński
2013-03-12 22:37:13 UTC
Permalink
:
cut to skip noise
:

For your leisure, citation from MASM 6.1 Programmers Guide (pages 198-200):

When you use the PROC directive with its extended syntax and argument
list, the assembler automatically generates the prologue and epilogue
code in your procedure. “Prologue code” is generated at the start of the
procedure. It sets up a stack pointer so you can access parameters from
within the procedure. It also saves space on the stack for local
variables, initializes registers such as DS, and pushes registers that
the procedure uses. Similarly, “epilogue code” is the code at the end of
the procedure that pops registers and returns from the procedure.

The assembler automatically generates the prologue code when it
encounters the first instruction or label after the PROC directive. This
means you cannot label the prologue for the purpose of jumping to it.
The assembler generates the epilogue code when it encounters a RET or
IRET instruction. Using the assembler- generated prologue and epilogue
code saves time and decreases the number of repetitive lines of code in
your procedures.
:
The assembler generates standard epilogue code when it encounters a RET
instruction without an operand. It does not generate an epilogue if RET
has a nonzero operand. To suppress generation of a standard epilogue,
use RETN or RETF with or without an operand, or use RET 0.

Tomek
Binarus
2013-03-07 12:25:14 UTC
Permalink
Post by Binarus
So may I hope that JWasm gets changed to avoid that bug?
No. This isn't a bug, the behavior is documented and intentional - if you code RETN or RETF, no epilogue is generated. Btw, it's not just jwasm and masm that behave this way, but also wasm and tasm.
As chance would have it, the project that I am porting is originally Borland (C++ 5.02 and TASM). So I can confirm that TASM does not generate the epilogue, but I also can tell for sure that it does not generate the prologue as well.

I'd like to emphasize that it's not the fact that the epilogue is missing that disturbs me, but the imbalance between prologue and epilogue. Either generate both or generate none ...

But as it's now clear now that this behavior is expected and intended and not due to a severe error from my side, I am sure I can live with it. I'll use one of the solutions which have already been mentioned in this thread.

Thanks for all the help, and thanks for the great JWasm!

Regards,

Binarus
Kevin Rhoads
2013-04-29 17:24:19 UTC
Permalink
Post by Binarus
I'd like to emphasize that it's not the fact that the epilogue is
missing that disturbs me, but the imbalance between prologue and
epilogue. Either generate both or generate none ...
Well, bottom line, that is what you expect for HLLs. For assemblers you
expect more flexibility. IIRC there were many who were annoyed and
dismayed by the amount of "auto" stuff Microsoft 8086/8088 assemblers
did and the amount declarations they required back in the early 1980s.
japheth
2013-05-03 08:42:43 UTC
Permalink
Post by Kevin Rhoads
Post by Binarus
I'd like to emphasize that it's not the fact that the epilogue is
missing that disturbs me, but the imbalance between prologue and
epilogue. Either generate both or generate none ...
Well, bottom line, that is what you expect for HLLs. For assemblers you
expect more flexibility. IIRC there were many who were annoyed and
dismayed by the amount of "auto" stuff Microsoft 8086/8088 assemblers
the "auto" stuff can always be avoided if wanted.
Post by Kevin Rhoads
did and the amount declarations they required back in the early 1980s.
this "red tape" argument was invented by a few authors to sell the lacking
functionality of their assemblers as advantages ( esp. ASM86 and NASM ).
Binarus
2013-05-08 09:55:58 UTC
Permalink
Post by Kevin Rhoads
Post by Binarus
I'd like to emphasize that it's not the fact that the epilogue is
missing that disturbs me, but the imbalance between prologue and
epilogue. Either generate both or generate none ...
Well, bottom line, that is what you expect for HLLs.
I'm not sure if I get you right here. JWasm is an assembler and not a HLL (assuming that HLL means High Level Language), is it? So why should we expect such behavior?
Post by Kevin Rhoads
For assemblers you
expect more flexibility.
Yes. But more flexibility IMHO means that the assembler only assembles the source and does not insert additional opcodes which aren't in the source. Personally, I consider adding such opcodes being an unwanted automatism. This of course includes adding a prologue, let alone adding a prologue without a corresponding epilogue.

But since many people have explained the situation in this thread, I really can live with that behavior of JWasm. I just have added the epilogue at the end of each procedure where JWasm inserts a prologue, and this works like expected.

Best regards,

Binarus

Uwe Schmelich
2013-03-05 16:51:52 UTC
Permalink
Post by Binarus
Post by Uwe Schmelich
Post by Binarus
Uwe, thanks for helping. Here is an example (of course, it does nothing
meaningful, but shows the problem).
;***********BEGIN OF CODE
.586p
;----------------------------------------
;----------------------------------------
;----------------------------------------
test_TEXT SEGMENT WORD PUBLIC USE16 'CODE'
;----------------------------------------
PUBLIC C E820_FetchEntry
;---------------------------------
;---------------------------------
E820_FetchEntry PROC FAR C,
pul_BiosBlock: PTR FAR DWORD,
pv_Buffer: PTR FAR BYTE,
pui_Carry: PTR FAR WORD,
pul_Signature: PTR FAR DWORD,
pul_BytesWritten: PTR FAR DWORD
;----------------------------
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH EDI
PUSH ES
MOV EAX, [pul_BiosBlock]
LES DI, [pv_Buffer]
MOV EBX, [pui_Carry]
MOV ECX, [pul_Signature]
MOV EDX, [pul_BytesWritten]
POP ES
POP EDI
POP EDX
POP ECX
POP EBX
POP EAX
RETF
;--------------------
E820_FetchEntry_ ENDP
;--------------------
;--------------------
;------------
test_TEXT ENDS
;------------
;------------
;------------
END
;********END OF CODE
To reproduce the problem, pleas save the code above in a file called
jwasm -5p -e20 -FPi87 -fp3 -Gd -W4 -WX -zcm -omf test.asm
You now should have an object file called test.obj. Now let's
wdis test.obj
**********************BEGIN OF WDIS OUTPUT
Module: test.asm
Segment: TEST_TEXT WORD USE16 0000002D bytes
0000 55 push bp
0001 8B EC mov bp,sp
0003 66 50 push eax
0005 66 53 push ebx
0007 66 51 push ecx
0009 66 52 push edx
000B 66 57 push edi
000D 06 push es
000E 66 8B 46 06 mov eax,dword ptr 0x6[bp]
0012 C4 7E 0A les di,dword ptr 0xa[bp]
0015 66 8B 5E 0E mov ebx,dword ptr 0xe[bp]
0019 66 8B 4E 12 mov ecx,dword ptr 0x12[bp]
001D 66 8B 56 16 mov edx,dword ptr 0x16[bp]
0021 07 pop es
0022 66 5F pop edi
0024 66 5A pop edx
0026 66 59 pop ecx
0028 66 5B pop ebx
002A 66 58 pop eax
002C CB retf
Routine Size: 45 bytes, Routine Base: TEST_TEXT + 0000
No disassembly errors
**********************END OF WDIS OUTPUT
The first two instructions are a typical __cdecl stack frame and got
compiled in automatically, hopefully due to the "C" qualifier I have
used for declaring and defining the procedure. That's what I wanted and
expected.
But what's the reason for no "pop bp" being at the end of the procedure?
Without it, the code program will definitely be continued at the wrong
place after the retf.
Thank you very much,
Binarus
Ok, I was able to reproduce it. The behaviour is the same with jwasm and
masm10, so at least jwasm is compatible with masm here. If you use 'ret'
instead of 'retf' then a 'pop bp' is generated by jwasm and a 'leave' by
masm. If you want the 'leave' in jwasm too, you have to use the
additional parameter -Zg.
Uwe
Uwe, thank you very much.
First of all, I can confirm that if I use ret instead of retf the "pop bp"
at the end of the PROC is generated automatically. I don't need the leave,
at least in most cases, since PUSHs and POPs are usually balanced in my
assembler code.
Besides that, I think that JWasm's behavior (as well as MASM's) is buggy.
1) Consequently use ret instead of retf. IMHO, this is bad style, very
hard to understand by others and quite dangerous. As soon as you are
trying to compile that code using other assemblers (outside the MASM
sphere), probably the opcode for ret (C3) will be inserted at the end of
the PROC instead of retf (CB), meaning that the code will crash.
2) Keep using retf and manually add the pop bp at the end of the PROC.
This is as bad as 1) for the same reason: Another assembler (if behaving
well) will insert the stack frame at the beginning *and* the end of the
PROC, and then you are ending up with the pop bp doubled at the end, once
again meaning that the code will crash.
3) Use -Zg. But what if we don't need the implicit MOV SP, BP which is part of LEAVE?
Well, probably we could discuss for a long time which of the three
alternatives is the best one, or which one is acceptable.
But I think that automatically inserting operations which leave the stack
*unbalanced* in every case is a severe bug that must be avoided under all
circumstances.
So may I hope that JWasm gets changed to avoid that bug? - Well, during
thinking about it, that would probably mean that the compatibility to MASM
would be broken, but perhaps we could introduce a new command line switch
which allows the user to choose between the buggy MASM behavior and a
correct behavior?
Thank you very much!
Regards,
Binarus
I imagine the philosophy of MASM is that if you use PROC/ENDP then the
assembler decides itself if retn or retf is required depending on the PROC.
If you set it yourself, then you are on your own.
So you could remove the PROC and do it all on your own. Or use ret.
Or maybe create a macro myret as pop bp,ret. So, if you use another
assembler you could change that macro. BTW, are there that many masm
compatible assemblers besides masm/jwasm?
The switch -Zg is not a real solution because it only changes the emiting
of 'pop bp' vs. 'leave'. It doesn't help with retf.

You may file an enhancement request at
http://sourceforge.net/tracker/?group_id=255677&atid=1126896
for your new switch for jwasm if you like.

Uwe
Binarus
2013-03-07 12:35:49 UTC
Permalink
Post by Uwe Schmelich
I imagine the philosophy of MASM is that if you use PROC/ENDP then the
assembler decides itself if retn or retf is required depending on the PROC.
If you set it yourself, then you are on your own.
So you could remove the PROC and do it all on your own. Or use ret.
Or maybe create a macro myret as pop bp,ret. So, if you use another
assembler you could change that macro. BTW, are there that many masm
compatible assemblers besides masm/jwasm?
The switch -Zg is not a real solution because it only changes the emiting
of 'pop bp' vs. 'leave'. It doesn't help with retf.
You may file an enhancement request at
http://sourceforge.net/tracker/?group_id=255677&atid=1126896
for your new switch for jwasm if you like.
Uwe, thank you very much for your suggestions.

I still think that an assembler can choose if a prologue / epilogue is generated (dependent on command line switches, calling convention and so on), but if it chooses to automatically insert stack frames, it should do so in "balanced" fashion - either generate prologue and epilogue or generate none of them.

I initially thought that the (worrying, well, at least for me) behavior was due to an error on my side. I now have learned that this is not the case, so the whole thing is not a real problem any more. I'll use one of the solutions which have already been mentioned in this thread (including yours).

Regards,

Binarus
Wilton Helm
2013-03-14 22:59:16 UTC
Permalink
The reality here though is that PROC and ENDP are macros. So is RET. The
intent is that if you use PROC and ENDP you will also use RET. They
function as a set.
Wilton Helm
2013-03-14 22:56:34 UTC
Permalink
Part of what PROC does for you (unless explicity overridden with near or
far) is to use the nearness or farness of the memory model to automatically
create correct code. When RET is used, the correct form (near or far) is
automatically supplied, so the same file could be used in either a small
code or large code model without change. Other macros work with that to
make it possible in many cases to write model independent code in assembly.
Expecting RET in a proc, therefore is not a bug or vulnerability. It is a
feature.

Wilton
Loading...