user2338150
user2338150

Reputation: 479

Automatic code insertion in tasm

I am trying to write a simple C startup to produce DOS COM file. I have not yet written argc, argv implementations. As a test, I'm trying to put dummy argv[0], and argc=1. But I get 2 unexpected lines as in the dump :

;---------------------------------------------------------------

Turbo Debugger Log

CPU 80486

  cs:0100B85902          mov    ax,0259                      
  cs:0103 50             push   ax                           
  cs:0104 BF5002         mov    di,0250                      
  cs:0107 FF35           push   word ptr [di]                
  cs:0109 90             nop                   ; << Unexpected 1              
  cs:010A 0E             push   cs             ; << Unexpected 2               
  cs:010B E83C00         call   014A                         
  cs:010E E80000         call   0111                         
  cs:0111 B44C           mov    ah,4C                        
  cs:0113 CD21           int    21                           
  cs:0115 55             push   bp                           
  cs:0116 8BEC           mov    bp,sp                        
  cs:0118 8B4604         mov    ax,[bp+04]                   
  cs:011B 50             push   ax                           
  cs:011C B40E           mov    ah,0E                        
  cs:011E CD10           int    10                           
  cs:0120 58             pop    ax                           
  cs:0121 5D             pop    bp                           
  cs:0122 C3             ret                                 
  cs:0123 50             push   ax                           
  cs:0124 55             push   bp                           
  cs:0125 8BEC           mov    bp,sp                        
  cs:0127 C746026900     mov    word ptr [bp+02],0069        
  cs:012C 5D             pop    bp                           
  cs:012D E8E5FF         call   0115                         
  cs:0130 59             pop    cx                           
  cs:0131 C3             ret                                 
  cs:0132 55             push   bp                           
  cs:0133 8BEC           mov    bp,sp                        
  cs:0135 56             push   si                           
  cs:0136 33F6           xor    si,si                        
  cs:0138 EB01           jmp    013B                         
  cs:013A 46             inc    si                           
  cs:013B 8B5E04         mov    bx,[bp+04]  

Terminated, exit code 7

Stack :

5B7C:0028 FFFF  
5B7C:0026 FFFF  
5B7C:0024 FFFF  
5B7C:0022 FFFF  
5B7C:0020 FFFF  
5B7C:001E FFFF  
5B7C:001C FFFF  
5B7C:001A FFFF  
5B7C:0018 FFFF  
5B7C:0016 0DEE  
5B7C:0014 1C80  
5B7C:0012 0280  
5B7C:0010 2225  
5B7C:000E 01AE  
5B7C:000C 2225  
5B7C:000A 01E4  
5B7C:0008 F01D  
5B7C:0006 FEF0  
5B7C:0004 9A00  
5B7C:0002 9FFF  
5B7C:0000 20CD  
5B7C:FFFE 0000  
5B7C:FFFC 0259  ; << argv

5B7C:FFFA 0001  ; << argc  

5B7C:FFF8 5B7C  ; << Unexpected CS

5B7C:FFF6 0111  
5B7C:FFF4 3206  
5B7C:FFF2 5B7C  
5B7C:FFF0 0115  
5B7C:FFEE 3206  

;---------------------------------------------------------------

I could not understand why these lines are added by the assembler. Could segment-padding be the cause? Also, could there be a stack-frame 'like' construct? Please enlighten me on this. Here's the source :

;---------------------------------------------------------------
_TEXT   SEGMENT WORD PUBLIC USE16 'CODE'
_TEXT   ENDS
_DATA   SEGMENT WORD PUBLIC USE16 'DATA'
_DATA   ENDS
DGROUP  GROUP   _DATA , _TEXT



_TEXT   SEGMENT
    assume  cs: _TEXT, ds: _DATA, ss: nothing, es: nothing


    ORG 0100h

;----------------------------------
; Program Starts Here...
;----------------------------------
start:

    ; Push arguments in reverse order...
    ;====================================

    mov ax, offset DGROUP:argv
    push    ax

    mov di, offset DGROUP:argc
    push    word ptr [di]

    call    far ptr _main
    call near ptr __terminate

;----------------------------------


;----------------------------------
; Function Declarations...
;----------------------------------

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
__terminate     proc    DIST
    PUBLIC  __terminate
    mov ah, 4ch
    int 21h
__terminate     endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;----------------------------------

_TEXT   ends

_DATA   SEGMENT


argc    dw  1
arg0    db  'NEW_C0', 0h
argv    dw  DGROUP:arg0

_DATA   ENDS

    extrn   _main

end start
;---------------------------------------------------------------

Upvotes: 2

Views: 301

Answers (1)

Ruud Helderman
Ruud Helderman

Reputation: 11018

From a document I found titled "Turbo Assembler 2.0 New Features":

The default condition is SMART enabled. When SMART is enabled, a qualifying FAR jump will be replaced by a NEAR or a SHORT jump. Also, when SMART is enabled, a qualifying FAR call will be replaced by a PUSH CS instruction and a NEAR call.

So TASM, being smart at recognizing that _main and your startup code are in the same segment (you are producing a COM file, after all), takes the liberty to replace:

call    far ptr _main

by the shorter and faster near call:

push    cs
call    _main

The push is necessary because TASM must assume that main itself was compiled with a far return; it expects a 32-bit return address on the stack.

You should ask yourself whether you actually want/need this far call in a COM file.

As for the nop, I have no idea. It could be word padding in an effort to make the far return more efficient, but I find Jester's explanation (reserve space for a true far call) very plausible too.

Upvotes: 4

Related Questions