News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

USE directive error

Started by 2B||!2B, June 03, 2019, 02:41:19 PM

Previous topic - Next topic

2B||!2B

Hi,

I read the PDF of UASM but i cannot get the USE directive to work.

USE64


xor ax,ax
xor eax,eax
xor rax,rax

: Error A2169: General Failure

What is the error?

2B||!2B

I found a fix for this problem.
In case anyone is facing the same issue, here is how to fix it.

add these on top of the project

option flat:1
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE


However, there are still some issues that need to be resolved.

: Warning A4299: BSS data in BIN output could have side effects

Using USE, this will cause the compiled project to have 2 code sections.
.text
_flat


That will cause problems with all .data writing at runtime since the _flat section is not writeable and now it has replaced the .data section.
I am waiting for some clarification from the coder. Maybe i am doing something wrong here.

aw27

I would suggest you to produce a complete example, including showing how you are trying to build it.
Odds are you doing things wrong, so this will save people time as well as tear and wear of the brain cells
Some people can't even read properly the manual before asking questions, this may or not be your case - I believe it is your case because the sample provided in the manual builds successfully.


2B||!2B

Hi AW,

Thanks for the tip.
Is just copied and pasted from the manual to an empty project, thats why i did not post project files.
I also managed to fix that by posting later on.
The new issue is different and is the aftermath.
I will post the files in here.

2B||!2B

I attached a sample that demonstrates the issue.

The Val variable is set to be in .data? section. However, when compiling, .data section is been merged into _flat section which has no writeable flag and thus causing access violation exception.

Access violation when writing to [00401000]



jj2007

That is indeed weird. Here is the essential code:
.486
.model flat,stdcall
option casemap:none
option flat:1
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

.data?
Val dd ?

.code
start:
     use64
        POP rax
        MOV RCX, RAX

     use32
      MOV EAX,1
      MOV Val,EAX
        RET
end start


As seen from Olly:
00401000       .  00000000                    dd 00000000
<ModuleEntryP Ú$  58                          pop eax
00401005      ³.  48                          dec eax
00401006      ³.  8BC8                        mov ecx, eax
00401008      ³.  B8 01000000                 mov eax, 1
0040100D      ³.  A3 00104000                 mov [401000], eax
00401012      À.  C3                          retn


The mov [401000], eax causes the exception :sad:

Another interesting question, though, is how the cpu knows that instead of the pop eax it must perform a pop rax :rolleyes:

aw27

Weird is that half of the chapter explains the scope for the clauses and even hints how to build things. Regardless of that, people still apply the same old receipt of one size fits all.

LiaoMi

Hi,

debug build does not work

mywindow2useBug.asm(9) : Warning A4299: BSS data in BIN output could have side effects
mywindow2useBug.asm(9) : Warning A4299: BSS data in BIN output could have side effects
mywindow2useBug.asm : Error A2197: Unknown fixup type: 10 at .debug$S.37
mywindow2useBug.asm : Error A2197: Unknown fixup type: 10 at .debug$S.55
mywindow2useBug.asm : Error A2197: Unknown fixup type: 10 at .debug$S.124



Some in-depth information (question and answer is completely copied) - Effects of the FLAT operand to the SEGMENT directive? https://stackoverflow.com/questions/45124341/effects-of-the-flat-operand-to-the-segment-directive

MASM provides a SEGMENT directive. The directive takes several parameters. The use parameter can take a value FLAT. It's unclear to me what this value does.

The Microsoft docs https://docs.microsoft.com/en-us/cpp/assembler/masm/segment specify it as an accepted value but make no attempt to describe it:

use
USE16, USE32, FLAT


The book The Art of Assembly Language Programming available online mentions it but calls it out of scope and recommends reading the MASM Programmer's Guide:

The use32 and flat operands tell MASM to generate code for a 32 bit segment. Since this text does not deal with protected mode programming we will not consider these options. See the MASM Programmer's Guide for more details.

In the MASM 6.1 Programmer's Guide from Microsoft, in the section describing the SEGMENT directive, the FLAT value is mentioned but its effects are never described:

The size attribute can be USE16, USE32, or FLAT.

What are the effects of the FLAT operand to the SEGMENT directive?

Answer:

For most purposes the FLAT keyword when used in a segment directive has the same meaning as USE32. Both the USE32 and FLAT keywords indicate that the segment can be bigger than 64K and that any instructions assembled in the segment should use 32-bit encoding rather than 16-bit encoding. The difference is what the assembler assumes about the CS register. Normally a SEGMENT directive results in an implicit ASSUME CS:xxx directive where xxx is the name of the segment, but with FLAT it results in an implicit ASSUME CS:FLAT.

The ASSUME directive tells the assembler which segments are loaded into which segment registers so it can automatically use the correct segment overrides where needed. In the flat memory model used by most 32-bit operating systems there only one single 4 gigabyte segment. Telling the assembler that it can assume a segment register is FLAT tells the assembler that all segments defined in the program can be accessed through that segment register. For example ASSUME DS:FLAT says that all segments can accessed through the DS register. On the other hand ASSUME DS:_DATA says that the DS register can only be used to access the _DATA segment and not any other segment.

You can see this behaviour by assembling the following code:

_DATA   SEGMENT PUBLIC USE32
var DD  ?
_DATA   ENDS

_TEXT   SEGMENT PUBLIC PARA 'CODE' FLAT

    mov eax, [zero]
    mov [var],eax

    ASSUME  DS:FLAT

    mov eax, [zero]
    mov [var],eax

    ASSUME  CS:_TEXT 
    ASSUME  DS:_DATA

    mov eax, [zero]
    mov [var],eax

zero    DD  0

_TEXT   ENDS

    END

If you disassemble the resulting object file you see this for the first two instructions:

  00000000: 2E A1 00 00 00 00  mov         eax,dword ptr cs:[zero]
  00000006: 2E A3 00 00 00 00  mov         dword ptr cs:[var],eax

For these two instructions the assembler has to use the CS segment override (2E) in order to access zero and var. That's because while the assembler knows that CS can be used to access all segments, including _TEXT and _DATA, it doesn't know that any other segment register can be used to access these semgents.

Here's the code it generates for the next two instructions, after the ASSUME DS:_FLAT directive:

  0000000C: A1 00 00 00 00     mov         eax,dword ptr [zero]
  00000011: A3 00 00 00 00     mov         dword ptr [var],eax

Now the assembler knows that both CS and DS can be used to access all segments. Since using DS to access zero and var doesn't require a segment override, it uses DS instead of CS resulting in shorter instructions.

Finally the last two instructions, after the ASSUME DS:_DATA and ASSUME CS:_TEXT directives, show the code assembler would generate if the FLAT keyword isn't used at all:

  00000016: 2E A1 00 00 00 00  mov         eax,dword ptr cs:[zero]
  0000001C: A3 00 00 00 00     mov         dword ptr [var],eax

In this case the assembler assumes CS can only be used to access _TEXT, and DS only to access _DATA. It has to use a CS override to access zero, while it can only access var through DS, which requires no segment override.

Note if you change the FLAT to USE32 in the SEGMENT directive in the example code above then first instruction ends up using a CS override, but the second instruction generates the following error:

error A2074:cannot access label through segment registers

That's because while the assembler knows it can access _TEXT through the CS register, it doesn't know of any segment register it can use to access _DATA.

If you use the .MODEL FLAT directive at the start of you code you shouldn't have to worry about any of this. Then USE32 and FLAT have exactly same effect in segment directives as every segment register is assumed to be FLAT.

LiaoMi

workaround once downloaded in one of the topics on the forum :thumbsup:

.386
.model flat

includelib msvcrt.lib
exit proto C :dword
_getch proto C
printf proto C :dword, :vararg

call_as_x64 macro lbl
    db 9ah         ;call 0x33:OFFSET x64-proc
    dd OFFSET lbl
    dw 33h
endm

.x64
x64 SEGMENT EXECUTE USE64

; let's do some 64 bit arithmetic
mov eax,DWORD ptr [rsp+8]
mov r10,QWORD ptr [rax]
shr r10,16
mov QWORD ptr [rax],r10

retf

x64 ENDS

.data
fmt1 db "%p%p",13,10

.code
main proc
;LOCAL sysi:SYSTEM_INFO
LOCAL myQW:QWORD
mov DWORD ptr myQW[0],0AAAAAAAAh
mov DWORD ptr myQW[4],0BBBBBBBBh
invoke printf, addr fmt1, dword ptr myQW[4], dword ptr myQW[0]
lea eax,myQW
push eax
call_as_x64 x64
invoke printf, addr fmt1, dword ptr myQW[4], dword ptr myQW[0]
invoke _getch
invoke exit,0
main endp
end main

LiaoMi

#9
 :thumbsup:

.586
.MODEL FLAT, C
.STACK
.DATA
KeyKey dd 10000000h
.CODE             ;Indicates the start of a code segment.

mainCRTStartup PROC; run_asm64
db 0EAh    ; jump to enter 64 bit
dd offset LocEnter
db 033h, 000h
LocEnter:
; Add the 64bit opcodes within the two lines
; warning: remember to preserve the registers you trash
;-----------------------------------------------------
db 051h, 048h, 0b9h                              ; push rcx / mov rcx, offset Key
dd offset KeyKey
dd 0
db 081h, 001h, 078h, 056h, 034h, 012h, 059h      ; add dword ptr [rcx], 012345678h / pop rcx
;----------------------------------------------------
db 048h, 083h, 0ech,
004h
; sub  rsp,4

db 089h, 004h,
024h 
; mov  dword ptr [rsp], eax (save eax forlater)

db 048h, 08bh,
0c4h 
; mov rax,rsp

db 06ah,02bh   
; push stack segment selector

db 50h   
; push stack pointer (in rax)

db 068h, 046h, 002h, 000h,
000h
; push eflags

db 06ah, 023h   
; push code selector
db 068h
dd offset LocExit   ; push instruction pointer
db 048h, 0cfh    ; iretq
LocExit:
pop eax     ; restore eax
ret

mainCRTStartup ENDP ; run_asm64
END


also does not work ..

.486
.model flat,stdcall
option casemap:none
option flat:1
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

.data?
;zero    DD  0
Val dd ?

.code
start:
new proc
;jmp far ptr 33h:use64Enter
db 0EAh    ; jump to enter 64 bit
dd offset use64Enter
db 033h, 000h
use64Enter:
     use64
        POP rax
        MOV RCX, RAX
push LocExit   ; push instruction pointer
        iretq
LocExit:
     use32
      MOV EAX,1
      MOV Val,EAX
        RET
new endp
end start


From the documentation ...

6. OPTION FLAT

For some types of low-level programming, especially OS kernel and boot-loader code the model
adopted by some other non-MASM style assemblers lends itself very well to mixing code of
different bit types, for example switching between real and protected or long mode.
To make this type of programming more straight-forward UASM implements a flat mode. A single
code section is create with the normal .code simplified directive, however the new directives
USE16/USE32/USE64 can be used on their own to switch the current code-generation mode.
For example:
option flat:1



.code

org 0h
USE16

xor ax,ax
xor eax,eax


org 100h
var1 dd 10

USE32
xor ax,ax
xor eax,eax

org 1000h
var2 dd 20

USE64

xor ax,ax
xor eax,eax
xor rax,rax

LiaoMi

Another example  :tongue:

mywindow2useBug.asm(10) : Warning A4299: BSS data in BIN output could have side effects
mywindow2useBug.asm(17) : Error A2069: Segment, group or segment register expected
mywindow2useBug.asm: 35 lines, 1 passes, 2 ms, 1 warnings, 1 errors
Microsoft (R) Incremental Linker Version 14.21.27702.2
Copyright (C) Microsoft Corporation.  All rights reserved.


.486
.model flat,stdcall
option casemap:none
option flat:1
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE

.data?
Val dd ?

.code
start:
new proc
        XOR ECX, ECX
        CALL 33h:Our64Proc ; <- Error A2069: Segment, group or segment register expected
      MOV EAX,1
      MOV Val,EAX
        RET
new endp

Our64Proc proc  ;This proc is x64 code
     use64
        CALL @F
        DB "This was generated using 64 bit ASM code.", 0
@@:
        POP RAX
        MOV RCX, RAX
     use32
        RETF
Our64Proc endp

end start

aw27

It is very clear in the manual (although extremely terse  :sad:) what is the purpose of this. It is also very clear (:joking:) that we were expected to produce BIN output, i.e use a special switch that UASM has, the BIN switch. If all this sounds like a riddle, it is indeed a riddle.  :skrewy:

So I produced an example that everybody can run without having to format floppy disks or other unusual practice. The example, is an extremely small .exe file.

You must test by running the included test.bat, not the mixedCode.exe.


hutch--

 :skrewy:

Expected return value is 123456. Returned value is: 123456
Press any key to continue . . .

johnsa

Hi,

Just to add to what AW has been saying.

The purpose of USE16, USE32, USE64 directives is to work in conjunction with option flat:1

This is a "special" mode not for general use under Windows, Linux etc.

It must be used with -BIN output type.

It will generate a flat binary image without segments (while still allowing simplified directives like .code) that can assemble instructions based on the current state (IE: USE16, USE32, USE64).
If you are familiar with any boot loading, kernel code these constructs become very handy and it replicates a style of coding/usage similar to that available in FASM.

for example, if you wanted to write a a block of code which had some real mode 16bit stuff and some 32bit protected mode stuff, instead of having:


code16 segment para public use16 'code16'
assume cs:code16
.
.
jmp far ptr lbl2
.
.

code32 segment para public use32 'code32'
assume cs:code32

lbl2:


as you might with MASM, and often then you have to hack or hand-code in the far jumps.

instead you can do something like:


USE16

mov ax,13h
int 10h
jmp far ptr lbl2

USE32

; Here we are in protected mode..
lbl2:


Obviously I've left out lots of the code above but you get the idea..I implemented this mode specifically for OS development stuff I was working on.
It also allows correct evaluation of org directives, offsets and addr across different bit-sizes (keeps your life a bit simpler).

2B||!2B

Thank you guys for the contribution.
I understand the use now.
My bad, i thought the USE directive can be used with normal PE files like the one in FASM.