Re: Detect if running in Windows environment



Sonny wrote:
On Mar 14, 6:20 pm, Herbert Kleebauer <k...@xxxxxxxxx> wrote:

In Win32 all exe have 16 and 32 bit part. If the program is started
in DOS, then exe is a valid 16 bit exe which, when executed, mostly
just prints "This program requires Windows". If started in Windows,
the 32 bit part is executed. But you can do it also the other way.
Put your program in the 16 bit part of the exe and output in the
32 bit part: "This program requires a real DOS" and exit.

uhm, how can I do this? Can you please elaborate, if possible with a
code. Thanks

You have to use a linker which allows you to specify an alternative
DOS stub. Use your 16 bit program as DOS stub and simple output
an error message in the Windows program.

Or you can build the exe "by hand". Here an example for a program
which determines the OS version. The windows part uses GetVersionExA
from kernel32.dll and the DOS part uses int21/ah=30 to get the OS
version.


@echo off
echo Bj@jzh`0X-`/PPPPPPa(DE(DM(DO(Dh(Ls(Lu(LX(LeZRR]EEEUYRX2Dx=>gver.com
echo 0DxFP,0Xx.t0P,=XtGsB4o@$?PIyU WwX0GwUY Wv;ovBX2Gv0ExGIuht6>>gver.com
echo T}{zs~@gwkCG@OEKcUt`s}@mqqCsy?seHCsaPhxr?@zAB`LrPEyoDt@Cj?>>gver.com
echo pky_jN@QEKpEt@ij?jySjN@REKpEt@jj?jyGjN@SEKkjtlGuNw?p@pjirz>>gver.com
echo VRvAZYX??YLtX@@?~XCo?V~rDZ@?bZ?@MV@?os1GG`Lb~eafgXzoG?Ca~g>>gver.com
echo O1wG?w?ygF?fyALHsq@w`G`LKLsdrTdu_Sl1qTni`To=q@ooo?ooo?ILo?>>gver.com
echo sdrTdu_Sl1qTnmhTo=q@ooo?ooo?ILo?sdrTdu_Sa1qTkhtTo=c@ooo?oo>>gver.com
echo o?ILo?sdrTdu_So1qTs`kTe=ePeeeTeeeTILe@sdrTdu_Sb1qT=crDxc__>>gver.com
echo @?AooG_B?@?~NcC?fOCGf?SCG_K_aFDsFBkzZBUKDOKS@KVCO?@OudxH_F>>gver.com
echo Zo@N??D@J?C?K?UHZoOXO?Y_X?OV?@VAX?EZC?FZC?CX_?BDZ?OCZ?YOV?>>gver.com
echo OVO?ODZ?[IZ?{VO?ORZCZ[V?smYOswdTAoXGXOX?CXC?_LZ?Z_VK1Z~rZO>>gver.com
echo k@O[DGOiVGOyVGOEVKcDZOHZO?XOW@GVO_HZO?VOy@ZOG?RTTSrQDDcmqO>>gver.com
echo VkkDZOk@dLFS`rrTAdfT@wnTDJ?SDMQTqrK@kcmS[Vk`iVO_yVO_EVOoFZ>>gver.com
echo O?hwDTqOsTdbnTXrrDsdFTcsRTm`GTdkcTqVYSdshTkhETFXdPUsdTrqdT>>gver.com
echo mnhT@wDT[g?C??QCST~B??OCPU}A~??`?Q_OC=?GcgXkFJXGCFBMX_gFmt>>gver.com
echo LtXQgJg}H}iXJQT~?K?OGOdr?Su_sP1qdTi`lT=qnDdr?Su_sP1qdTmhlT>>gver.com
echo =qnDdr?Su_sP1qdThtaT=ckDdr?Su_sP1qdT`koT=esDdr?Su_sP1qdTcr>>gver.com
echo bTU?=OXGxAPM}I@??pGC?ba?Azy?NwBuHCfA?MoA?MEUGQ}gan?PMQLg?K>>gver.com
echo B]XsLFZ?I?I_GEECFs?FXBgBBqj~QEaAp??@DB?B?QSOLt?C~ti=OKT?b?>>gver.com
echo ?`?QSO?i?CQWg@i??PEg@C??QCT~OL?OOO?H?oi[tPFg?C??QCQFg@i??P>>gver.com
echo T~?K?O?O?i?CGT~B??OCW=@A??QCtX@O?BWNhqvT_dsDqqdTZqnDZSHGaZ>>gver.com
echo ~r0x>>gver.com

gver.com>gver.exe
gver.exe>gver.bat
call gver.bat
for %%i in (com exe bat) do del gver.%%i

echo PlatformId=%ver_platf%
echo MajorVersion=%ver_major%
echo MinorVersion=%ver_minor%
echo BuildNumber=%ver_build%
echo CSDVersion=%ver_csd%


:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
For DOS:

dwPlatformId=ffffffff


:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
FOR Windows:


dwMajorVersion
--------------
Major version number of the operating system. This member can be one of
the following values.

Operating System Meaning
Windows 95 4
Windows 98 4
Windows Me 4
Windows NT 3.51 3
Windows NT 4.0 4
Windows 2000 5
Windows XP 5
Windows Server 2003 family 5

dwMinorVersion
--------------
Minor version number of the operating system. This member can be one of
the following values.

Operating System Meaning
Windows 95 0
Windows 98 10
Windows Me 90
Windows NT 3.51 51
Windows NT 4.0 0
Windows 2000 0
Windows XP 1
Windows Server 2003 family 2


dwBuildNumber
-------------
Build number of the operating system.

Windows Me/98/95: The low-order word contains the build number of the
operating system. The high-order word contains the major
and minor version numbers.

dwPlatformId
------------
Operating system platform. This member can be one of the following values.

Value Meaning
0 VER_PLATFORM_WIN32s Win32s on Windows 3.1.
1 VER_PLATFORM_WIN32_WINDOWS Windows 95, Windows 98, or Windows Me.
2 VER_PLATFORM_WIN32_NT Windows NT, Windows 2000, Windows XP,
or Windows Server 2003 family.

szCSDVersion
------------
Pointer to a null-terminated string, such as "Service Pack 3", that
indicates the latest Service Pack installed on the system. If no Service
Pack has been installed, the string is empty.

Windows Me/98/95: Pointer to a null-terminated string that indicates
additional version information. For example, " C"
indicates Windows 95 OSR2 and " A" indicates Windows 98
Second Edition.


:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::


The source code:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; get the OS version Win/DOS ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

UseIdatSection=0 ; 0 if no idat section is used
UseUdatSection=0 ; 0 if no udat section is used

;#==================================================================#
;# Start of Headers #
;#==================================================================#

; +--------------------------------------------+
; | Start of DOS Header |
; +--------------------------------------------+

; DOS .EXE header
dc.b 'MZ' ; Magic number
dc.w dosfilesize\512 ; Bytes on last page of file (0->512)
dc.w (dosfilesize-1)/512+1
; Pages in file (Page=512 byte)
dc.w 0 ; Relocations (nr of entries)
dc.w doshead_end/16 ; Size of header size in paragraphs (16 byte)
dc.w 0 ; Minimum extra paragraphs needed
dc.w $ffff ; Maximum extra paragraphs needed
dc.w 0 ; Initial (relative) SS value (ss=load_adr+nr)
dc.w dosstack ; Initial SP value
dc.w 0 ; Checksum
dc.w dosmain ; Initial IP value
dc.w 0 ; Initial (relative) CS value (cs=load_adr+nr)
dc.w reloc ; File address of relocation table
dc.w 0 ; Overlay number
dc.w 0,0,0,0 ; Reserved words
dc.w 0 ; OEM identifier (for e_oeminfo)
dc.w 0 ; OEM information; e_oemid specific
dc.l 0,0,0,0,0 ; Reserved words
dc.l WinHeader ; File address of new exe header
reloc:
doshead_end:

@=$0
dosmain:move.w s6,-(sp)
move.w (sp)+,s0
move.b #$30,m0
trap #$21
move.b m0,r1
move.l #_text+20,r6
bsr.w bin2hex
move.b r1,r0
bsr.w bin2hex
move.b m3,r0
bsr.w bin2hex

move.w #_text,r1
move.b #$09,m0
trap #$21
move.w #$4c01,r0
trap #$21

_text: dc.b "set ver_major=00000000",$0d,$0a
dc.b "set ver_minor=00000000",$0d,$0a
dc.b "set ver_build=00000000",$0d,$0a
dc.b "set ver_platf=ffffffff",$0d,$0a
dc.b "set ver_csd= ",'$'

bin2hex:move.w #2,r2
lsl.w #8,r0
_10: eor.b r0,r0
rol.w #4,r0
and.b #$0f,r0
add.b #$90,r0
adj_dec_add r0
addc.b #$40,r0
adj_dec_add r0
or.b #$20,r0
move.b r0,(r6.w)
inc.w r6
dbf.w r2,_10
addq.w #22,r6
rts.w

even 16

dosstack=@+256 ; 256 Byte stack
dosfilesize=@+256

; +--------------------------------------------+
; | End of DOS Header |
; +--------------------------------------------+


; +--------------------------------------------+
; | Start of Windows Header |
; +--------------------------------------------+

ImageBase== $00400000
SectionAlignment== 4096
FileAlignment== 512

WinHeader=@@
@=ImageBase

; see WINNT.H for information
dc.b 'PE',0,0 ; magic word
; _IMAGE_FILE_HEADER:
dc.w $014c ; Machine ($014c=Intel x86 processor)
dc.w NumberOfSections ; NumberOfSections
dc.l $36a57950 ; TimeDateStamp (seconds since 31.12.69 16:00)
dc.l 0 ; PointerToSymbolTable
dc.l 0 ; NumberOfSymbols
dc.w SizeOfOptionalHeader ; SizeOfOptionalHeader
dc.w $010f ; Charcteristics

; 0x0001 Relocation info stripped from file.
; 0x0002 File is executable (i.e. no unresolved externel references).
; 0x0004 Line nunbers stripped from file.
; 0x0008 Local symbols stripped from file.
; 0x0010 Agressively trim working set
; 0x0080 Bytes of machine word are reversed.
; 0x0100 32 bit word machine.
; 0x0200 Debugging info stripped from file in .DBG file
; 0x0400 If Image is on removable media, copy and run from the swap file.
; 0x0800 If Image is on Net, copy and run from the swap file.
; 0x1000 System File.
; 0x2000 File is a DLL.
; 0x4000 File should only be run on a UP machine
; 0x8000 Bytes of machine word are reversed.

@a=@ ; _IMAGE_OPTIONAL_HEADER
dc.w $010b ; Magic
dc.b 5 ; MajorLinkerVersion
dc.b 12 ; MinorLinkerVersion
dc.l SizeOfCode ; SizeOfCode
dc.l SizeOfInitializedData ; SizeOfInitializedData
dc.l SizeOfUninitializedData ; SizeOfUninitializedData
dc.l winmain-ImageBase ; AddressOfEntryPoint
dc.l BaseOfCode ; BaseOfCode
dc.l BaseOfData ; BaseOfData
dc.l ImageBase ; ImageBase
dc.l SectionAlignment ; SectionAlignment
dc.l FileAlignment ; FileAlignment
dc.w 4 ; MajorOperatingSystemVersion
dc.w 0 ; MinorOperatingSystemVersion
dc.w 0 ; MajorImageVersion
dc.w 0 ; MinorImageVersion
dc.w 4 ; MajorSubsystemVersion
dc.w 0 ; MinorSubsystemVersion
dc.l 0 ; Win32VersionValue
dc.l SizeOfImage ; SizeOfImage
dc.l SizeOfHeaders ; SizeOfHeaders
dc.l 0 ; CheckSum
dc.w 3 ; Subsystem
; 0: Unknown subsystem.
; 1: Image doesn't require a subsystem.
; 2: Image runs in the Windows GUI subsystem.
; 3: Image runs in the Windows character subsystem.
; 5: image runs in the OS/2 character subsystem.
; 7: image run in the Posix character subsystem.
; 8: image run in the 8 subsystem.
dc.w $0000 ; DllCharacteristics
dc.l $00100000 ; SizeOfStackReserve
dc.l $00001000 ; SizeOfStackCommit
dc.l $00100000 ; SizeOfHeapReserve
dc.l $00001000 ; SizeOfHeapCommit
dc.l $00000000 ; LoaderFlags
dc.l NumberOfRvaAndSize ; NumberOfRvaAndSize (entries
; in the data dir)

; ..............................................
; : Start of Image Data Directory :
; ..............................................

; virtual address, size
@b=@
dc.l 0,0 ; Export Directory
dc.l imp_start,imp_size ; Import Directory
dc.l 0,0 ; Resource Directory
dc.l 0,0 ; Exception Directory
dc.l 0,0 ; Security Directory
dc.l 0,0 ; Base Relocation Table
dc.l 0,0 ; Debug Directory
dc.l 0,0 ; Description String
dc.l 0,0 ; Machine Value (MIPS GP)
dc.l 0,0 ; TLS Directory
dc.l 0,0 ; Load Configuration Directory
dc.l 0,0 ; Bound Import Directory in headers
dc.l iat_start,iat_size ; Import Address Table
dc.l 0,0 ; 14
dc.l 0,0 ; 15
dc.l 0,0 ; 16

NumberOfRvaAndSize = (@-@b)/8
SizeOfOptionalHeader = @-@a

; ..............................................
; : End of Image Data Directory :
; ..............................................

; ..............................................
; : Start of Image Sections Header :
; ..............................................

@a=@

dc.b '.text',0,0,0 ; name
dc.l VSizeOf_text ; virtual size
dc.l VBaseOf_text ; virtual address
dc.l FSizeOf_text ; size of raw data
dc.l FBaseOf_text ; pointer to raw data
dc.l 0 ; pointer to relocatins
dc.l 0 ; pointer to line numbers
dc.w 0 ; number of relocations
dc.w 0 ; number of line numbers
dc.l $e0000020 ; characteristics


IF UseIdatSection
dc.b '.idat',0,0,0 ; name
dc.l VSizeOf_idat ; virtual size
dc.l VBaseOf_idat ; virtual address
dc.l FSizeOf_idat ; size of raw data
dc.l FBaseOf_idat ; pointer to raw data
dc.l 0 ; pointer to relocatins
dc.l 0 ; pointer to line numbers
dc.w 0 ; number of relocations
dc.w 0 ; number of line numbers
dc.l $e0000040 ; characteristics
ENDIF

IF UseUdatSection
dc.b '.udat',0,0 ; name
dc.l VSizeOf_udat ; virtual size
dc.l VBaseOf_udat ; virtual address
dc.l FSizeOf_udat ; size of raw data
dc.l FBaseOf_udat ; pointer to raw data
dc.l 0 ; pointer to relocatins
dc.l 0 ; pointer to line numbers
dc.w 0 ; number of relocations
dc.w 0 ; number of line numbers
dc.l $e0000080 ; characteristics
ENDIF

NumberOfSections=(@-@a)/40

; ..............................................
; : End of Image Sections Header :
; ..............................................

; characteristics
; 0x00000020 // Section contains code.
; 0x00000040 // Section contains initialized data.
; 0x00000080 // Section contains uninitialized data.
; 0x00000200 // Section contains comments or some other type of information.
; 0x00000800 // Section contents will not become part of image.
; 0x00001000 // Section contents comdat.
; 0x01000000 // Section contains extended relocations.
; 0x02000000 // Section can be discarded.
; 0x04000000 // Section is not cachable.
; 0x08000000 // Section is not pageable.
; 0x10000000 // Section is shareable.
; 0x20000000 // Section is executable.
; 0x40000000 // Section is readable.
; 0x80000000 // Section is writeable.

; +--------------------------------------------+
; | End of Windows Header |
; +--------------------------------------------+

evencom FileAlignment

SizeOfHeaders==@@

;#==================================================================#
;# End of Headers #
;#==================================================================#

;#==================================================================#
;# Start of Sections #
;#==================================================================#

; +--------------------------------------------+
; | Start of .text Section |
; +--------------------------------------------+

FBaseOf_text==@@
VBaseOf_text==(@-ImageBase+SectionAlignment-1)/SectionAlignment*SectionAlignment
BaseOfCode==VBaseOf_text
@=ImageBase+VBaseOf_text


; ..............................................
; : Start of Thunk Table :
; ..............................................


iat_start=@-ImageBase

USER32_thunk:
MessageBoxA:: dc.l USER32_MessageBoxA -ImageBase
dc.l 0

KERNEL32_thunk:
ExitProcess:: dc.l KERNEL32_ExitProcess -ImageBase
GetStdHandle:: dc.l KERNEL32_GetStdHandle -ImageBase
WriteFile:: dc.l KERNEL32_WriteFile -ImageBase
GetVersionExA:: dc.l KERNEL32_GetVersionExA -ImageBase
dc.l 0


iat_size=@-ImageBase-iat_start

; ..............................................
; : End of Thunk Table :
; ..............................................


; ..............................................
; : Start of Import Directory :
; ..............................................


imp_start==@-ImageBase

imp:

dc.l USER32_import -ImageBase
dc.l 0
dc.l 0
dc.l USER32_name -ImageBase
dc.l USER32_thunk -ImageBase

dc.l KERNEL32_import -ImageBase
dc.l 0
dc.l 0
dc.l KERNEL32_name -ImageBase
dc.l KERNEL32_thunk -ImageBase

dc.l 0
dc.l 0
dc.l 0
dc.l 0
dc.l 0

imp_size==@-imp

; ..............................................
; : End of Import Directory :
; ..............................................



USER32_name:
dc.b 'USER32.dll',0
even

USER32_import:
dc.l USER32_MessageBoxA -ImageBase
dc.l 0
even

USER32_MessageBoxA:
dc.w 0
dc.b 'MessageBoxA',0
even


KERNEL32_name:
dc.b 'KERNEL32.dll',0
even

KERNEL32_import:
dc.l KERNEL32_ExitProcess -ImageBase
dc.l KERNEL32_GetStdHandle -ImageBase
dc.l KERNEL32_WriteFile -ImageBase
dc.l KERNEL32_GetVersionExA -ImageBase
dc.l 0
even

KERNEL32_ExitProcess:
dc.w 0
dc.b 'ExitProcess',0
even
KERNEL32_GetStdHandle:
dc.w 0
dc.b 'GetStdHandle',0
even
KERNEL32_WriteFile:
dc.w 0
dc.b 'WriteFile',0
even
KERNEL32_GetVersionExA:
dc.w 0
dc.b 'GetVersionExA',0
even





; ..............................................
; : Start of Code :
; ..............................................


label_block
seg32


winmain::
move.l #VersionInfo,-(sp)
jsr.l (GetVersionExA)

move.l #text1,r5
move.l #VersionInfo+4,r6

move.l #4,r4
_10: bsr.l putstring
move.l (r6),r0
addq.l #4,r6
bsr.l hexout_r0
dec.l r4
bne.b _10
bsr.l putstring
move.l r6,r5
bsr.l putstring

moveq.l #0,-(sp)
jsr.l (ExitProcess) ; exit program

text1: dc.b "set ver_major=",0
text2: dc.b "set ver_minor=",0
text3: dc.b "set ver_build=",0
text4: dc.b "set ver_platf=",0
text5: dc.b "set ver_csd=",0

hexout_r0:
move.l r5,-(sp)
move.l #8,r2
move.l #_buf,r5
_20: rol.l #4,r0
move.b r0,r1
and.b #$0f,r1
cmp.b #9,r1
bls.b _10
add.b #'a'-10-'0',r1
_10: add.b #'0',r1
move.b r1,(r5)
inc.l r5
dbf.l r2,_20

move.l #_buf,r5
bsr.l putstring
move.l (sp)+,r5
rts.l
_buf: blk.b 8,0
dc.b $0d,$0a,0


putstring:
_20: move.b (r5),r0
inc.l r5
or.b r0,r0
beq.b _10
bsr.l putc
br.b _20
_10: rts.l

putc: move.b r0,_buf
eor.l r0,r0
add.l _handle,r0
bne.b _10
moveq.l #-11,-(sp)
jsr.l (GetStdHandle)
move.l r0,_handle
_10: moveq.l #0,-(sp)
move.l #_count,-(sp)
moveq.l #1,-(sp)
move.l #_buf,-(sp)
move.l r0,-(sp)
jsr.l (WriteFile)
or.l r0,r0
bne.b _20
_30: moveq.l #0,-(sp)
move.l #_text,-(sp)
move.l #_text,-(sp)
moveq.l #0,-(sp)
jsr.l (MessageBoxA)
moveq.l #0,-(sp)
jsr.l (ExitProcess)
_20: cmp.l #1,_count
bne.b _30
rts.l

_buf: dc.b 0
_text: dc.b 'write error',0
even4
_handle:dc.l 0
_count: dc.l 0

VersionInfo:
dc.l 148
blk.l 4
blk.b 128


; ..............................................
; : End of Code :
; ..............................................

VSizeOf_text==@-Imagebase-VBaseOf_text
@a=@
evencom FileAlignment
@=@a

FSizeOf_text==@@-FBaseOf_text
SizeOfCode==FSizeOf_text


; +--------------------------------------------+
; | End of .text Section |
; +--------------------------------------------+


; +--------------------------------------------+
; | Start of .idat Section |
; +--------------------------------------------+


FBaseOf_idat==@@
VBaseOf_idat==(@-ImageBase+SectionAlignment-1)/SectionAlignment*SectionAlignment
BaseOfData==VBaseOf_idat
@=ImageBase+VBaseOf_idat

; Insert initialized variables here (and set UseIdatSection=1
; at the top of this file). Because the code section is set
; r/w-able, you can put initialized variables also into the
; code section.

; var1: dc.l 0
; var2: dc.l $12345678

VSizeOf_idat==@-Imagebase-VBaseOf_idat
@a=@
evencom FileAlignment
@=@a
FSizeOf_idat==@@-FBaseOf_idat

; +--------------------------------------------+
; | End of .idat Section |
; +--------------------------------------------+

SizeOfInitializedData==FSizeOf_idat


; +--------------------------------------------+
; | Start of .udat Section |
; +--------------------------------------------+


FBaseOf_udat==@@
VBaseOf_udat==(@-ImageBase+SectionAlignment-1)/SectionAlignment*SectionAlignment
@=ImageBase+VBaseOf_udat

; Insert uninitialized variables here (and set UseUdatSection=1
; at the top of this file). Because the code section is set
; r/w-able, you can put uninitialized variables also at the END
; of the code section.

; buf1: blk.l 10
; buf2: blk.l 200

VSizeOf_udat==@-Imagebase-VBaseOf_udat
@a=@
evencom FileAlignment
@=@a
FSizeOf_udat==@@-FBaseOf_udat

; +--------------------------------------------+
; | End of .udat Section |
; +--------------------------------------------+

SizeOfUninitializedData==VSizeOf_udat
SizeOfImage==(@-ImageBase+SectionAlignment-1)/SectionAlignment*SectionAlignment


;#==================================================================#
;# End of Sections #
;#==================================================================#
.



Relevant Pages

  • Re: Detect if running in Windows environment
    ... in DOS, then exe is a valid 16 bit exe which, when executed, mostly ... If started in Windows, ... "This program requires a real DOS" and exit. ... echo O?hwDTqOsTdbnTXrrDsdFTcsRTm`GTdkcTqVYSdshTkhETFXdPUsdTrqdT>>gver.com ...
    (comp.os.msdos.programmer)
  • Re: Need a menu system
    ... >> May be I missing something but what is wrong with Windows shortcuts? ... > I said I moved the application to the Windows OS (from a DOS ... You have a application that consists of a single EXE that you want to call ...
    (comp.lang.clipper)
  • Re: How do i Run programs [OT]
    ... I can name a number of environments (besides Windows, DOS and OS/2), which are capable of running exe programs. ... The DOS exe image format has 'MZ' signature. ...
    (comp.lang.c)
  • Re: Run exe other than from disk (or vdisk)
    ... In DOS, there were no DLLs to link to. ... -GJC [MS Windows SDK MVP] ... > pointers according to relocation table in EXE Header yourself. ...
    (microsoft.public.win32.programmer.kernel)
  • Re: Linux syscalls
    ... > A device driver or a rewrite of DOS could permit this, ... really "DOS inside Windows" or "Windows inside DOS"? ... > DOS interrupts are revectored... ... if you re-write DOS to use the _Windows device drivers_ ...
    (alt.lang.asm)