Reputation: 479
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
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