KnowledgeBase Archive

An Archive of Early Microsoft KnowledgeBase Articles

View on GitHub

Q59608: A2071 and A2006 with Assembly Code from a C Program

Article: Q59608
Product(s): See article
Version(s): 5.10   | 5.10
Operating System(s): MS-DOS | OS/2
Keyword(s): ENDUSER | h_masm s_quickc s_quickasm fixlist6.00 | mspl13_c
Last Modified: 15-APR-1990

When using the /Fa switch (generate assembly language listing) and the
/AL switch (large memory model) with C 5.10, the compiler will
generate some slightly incorrect assembly code in the .ASM file. When
this assembly code is run through MASM, MASM will give the following
errors:

   A2071:  Forward needs override or FAR
   A2006:  Phase error between passes

Specifically, these errors occur in a module that has a function
calling another function within the same module. In this case, it is
possible to make a NEAR call to the specified function. Because the
function being called is a FAR function (in large memory model), CS
must be pushed onto the stack to correct problems that arise.

The assembly code produced by C 5.10 does not specify that the call to
the function is NEAR, although it still pushes CS onto the stack prior
to calling the function. Because the current memory model is large,
and the type of call is not specified, a FAR call is assumed.

When the function returns (with a RET), both CS and IP are popped off
of the stack, which the call automatically put onto the stack. You are
left with an extra CS still on the stack.

To work around this problem, it is important to force a NEAR call to
the function.

The following is an example of the C code used to produce the
assembly code:

#include <stdio.h>

void main (void);
int  r1   (void);

void main (void)
{
   printf ("Foo\n");
   r1 ();
   printf ("Bar\n");
}

int r1 (void)
{
   return (1);
}

The following is a piece of the assembly code, the important piece in
this case:
        .
        .
        .
   push  cs
   call  _r1
   mov   WORD PTR [bp-2], ax  ; rc
        .
        .
        .
Because these procedures are both declared as FAR, it is assumed that
this is a FAR call. Since that is the case, it is not necessary to
push CS.

To correct the problem, you can change the call to the following:
        .
        .
        .
   push  cs
   call  NEAR PTR _r1
   mov   WORD PTR [bp-2], ax  ; rc
        .
        .
        .
In this case, you are forcing the assembler to notice that only the
offset is necessary on the stack. When the RET is encountered, both
words (offset and segment) will be popped off of the stack.

It is necessary to make these changes for each call to a function that
can be made with a near call. Calls that are made to functions in
another module are FAR by default because they are external, so they
aren't a problem.

If the .ASM code is assembled with Quick Assembler, the same errors
will result if the two-pass option is turned on. With only one pass,
the phase error is not generated. Either way, the same correction
applies in both cases.

THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Copyright Microsoft Corporation 1986-2002.