News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Define bits in a structure

Started by minor28, September 25, 2011, 10:17:42 PM

Previous topic - Next topic

minor28

I know how to define this to masm

typedef struct MYSTRUCT
{
    struct {
DWORD Flags:12,
DWORD Size:4,
DWORD Max:16
}
    DWORD CodeSize;
} MYSTRUCT;


But how do I define this to masm

typedef struct MYSTRUCT
{
    unsigned Flags:12;
    unsigned Size:4;
    unsigned Max:16;
    DWORD CodeSize;
} MYSTRUCT;


Does anyone know how to do this?

Edit: First example was wrong

qWord

You can use RECORDs for this:
MYSTRUCT struct
xyz RECORD Max:16,_Size:4,Flags:12
codeSize DWORD ?
MYSTRUCT ends

However, the problem is, that you can't reuse the names Max, _Size and Flags for further bit field definitions...
It is probably better to declare the bit field as a DWORD and use EQUs for masking the bits.
FPU in a trice: SmplMath
It's that simple!

minor28

Thanks for your answer.

I have tryed that. It is compiled OK but not

mov MYSTRUCT.xyz,101111111110000000001111100000b
mov MYSTRUCT.xyz,-1

it returns "error A2006: undefined symbol"

This is OK as I did for the first example

xyz RECORD Max:16,_Size:4,Flags:12

MYSTRUCT struct
_xyz xyz <>
codeSize DWORD ?
MYSTRUCT ends

mov MYSTRUCT._xyz,101111111110000000001111100000b
mov MYSTRUCT._xyz,-1


How do I use EQUs for masking the bits?

And how do I define this structure

typedef struct MYSTRUCT
{
    CorExceptionFlag    Flags:16;
    unsigned            TryOffset:16;
    unsigned            TryLength:8;
    unsigned            HandlerOffset:16;
    unsigned            HandlerLength:8;
    union {
        DWORD       ClassToken;
        DWORD       FilterOffset;
    };
} MYSTRUCT;

NoCforMe

Quote from: minor28 on September 26, 2011, 07:38:33 AM
Thanks for your answer.

I have tryed that. It is compiled OK but not

mov MYSTRUCT.xyz,101111111110000000001111100000b
mov MYSTRUCT.xyz,-1

it returns "error A2006: undefined symbol"

Not sure, but it looks as if you used the STRUCT name (MYSTRUCT) instead of the name you used to declare the structure; you do know the difference between defining and declaring something, right?

In any case, please please please please please don't use ugly expressions like "101111111110000000001111100000b" in your code! Let me explain one way to handle this (not the only way, but I think a good one):

If you're going to use binary numbers to define a field, flag or variable, then do it ONCE only in an EQU:



$xyzValue EQU 101111111110000000001111100000b



(I like to prefix all my equates with "$" to distinguish them from variables)

Then you can set your variable thus:



MOV struc.xyz, $xyzValue



See how neat that is?

As someone else said, bit fields are best set up using EQUs instead of using MASM's RECORD operator. (I've never used it.) And I've really only used bit fields for single-bit flags. Those are easy to set up and use with equates:



$flagRed EQU 1
$flagGreen EQU 2
$flagTorn EQU 4
$flagRipped EQU 8
$flagSad EQU 10H
$flagHappy EQU 20H
$flagBroke EQU 40H
$flagRich EQU 80H

Flag DW ?

...

; Initialize the flag variable by zeroing it:
XOR AX, AX
MOV Flag, AX
; Now set a flag bit in it:
OR Flag, $flagRed
; Maybe set another flag (doesn't affect any other flags):
OR Flag, $flagRipped

; Later, test the variable for a certain bit:

TEST Flag, $flagRich ;Is the bit set?
JNZ got_money ;Yes, go somewhere


Notice I like to use hexadecimal bit assignments (1, 2, 4, 8, 10, 20, 40, 80, 100, 200, etc.). But if you prefer binary, that's fine too. Whatever works for you.

ToutEnMasm


Record is the badest  define that can be found in masm.
Field bits have there names global to the source code instead of local as in a structure.
The total names lenght  is limited inside the record.
records  allow you to use bit mask ,that all.

More usable is this form of declare:
Quote
   cpu_rflags_CF     equ   1 SHL 0
   cpu_rflags_PF     equ   1 SHL 2
   cpu_rflags_AF     equ   1 SHL 4
   cpu_rflags_ZF     equ   1 SHL 6
   cpu_rflags_SF     equ   1 SHL 7
   cpu_rflags_TF     equ   1 SHL 8
   cpu_rflags_IF    equ   1 SHL 9
   cpu_rflags_DF     equ   1 SHL 10
   cpu_rflags_OF     equ   1 SHL 11
   cpu_rflags_IOPL     equ   11b SHL 12
   cpu_rflags_NT     equ   1 SHL 14
   cpu_rflags_RF     equ   1 SHL 16
   cpu_rflags_VM     equ   1 SHL 17
   cpu_rflags_AC     equ   1 SHL 18
   cpu_rflags_VIF     equ   1 SHL 19
   cpu_rflags_VIP     equ   1 SHL 20
   cpu_rflags_D     equ   1 SHL 21
usage:
and eax,cpu_rflags_RF   ;and you have the bit 16 ,no need to remember how the mask directive work




jj2007

Records are indeed nasty animals, but here is a simpler version using the attached SetField and GetField macros.

Quoteinclude \masm32\include\masm32rt.inc
include MasmBasic_Record_Macros.inc   ; extract from MasmBasic

MyRecord RECORD Slot4:4, Slot7:7, Slot9:9   ; define record fields by name and # of bits

.data?

MyRec   MyRecord <>   ; define an empty 32-bit record with 3 fields
.code
start:
   SetField MyRec.Slot4, 5   ; set 2 of 4 bits (5=0101b)
   SetField MyRec.Slot4, 8   ; set bit 3, too - result should be 13
   
print "The content of MyRec.Slot4 is ", 9
   print str$(GetField(MyRec.Slot4)), 13, 10

   SetField
MyRec.Slot4, 7   ; set 3 of 4 bits (7=0111b)
   SetField MyRec.Slot4, 8, clear   ; set bit 3, clear the others - result should be 8
   
print "The content of MyRec.Slot4 is ", 9
   print str$(GetField(MyRec.Slot4)), 13, 10

   
mov eax, 111
   SetField MyRec.Slot7, eax   ; 7 bits aka 127 available, so 111 should be fine
   SetField MyRec.Slot9, -1   ; -1 means set all 9 bits

   
print "The content of MyRec.Slot7 is ", 9
   print str$(GetField(MyRec.Slot7)), 13, 10

   
print "The content of MyRec.Slot9 is ", 9
   mov ecx, GetField(MyRec.Slot9)
   print str$(ecx), 13, 10

   SetField
MyRec.Slot9, 123, clear   ; set to 123, clear other bits before
   
print "The content of MyRec.Slot9 is ", 9
   print str$(GetField(MyRec.Slot9)), 13, 10

   inkey "-- press any key --"
   exit
end start

Output:
The content of MyRec.Slot4 is   13
The content of MyRec.Slot4 is   8
The content of MyRec.Slot7 is   111
The content of MyRec.Slot9 is   511
The content of MyRec.Slot9 is   123

NoCforMe

jj, I must admit, that's some pretty nifty stuff, especially that whole MasmBasic thing you created. (I'll probably never use it myself, but it's still impressive.)

I'm just wondering, though: who on earth would really want to use bit fields in an actual program? Thinking back, the only time I've ever used them was to unpack the old DOS date/time structures--remember those? Even then, I never used the assembler, but just defined my own EQUs and did the necessary shifting and masking by hand.

Unless they have some use in reading bitmaps or something, I can't think of a problem that they'd be a good solution for.

Nice to know they're there just in case, though.

jj2007

#7
Yeah, I admit SetField is probably the most useless function in MasmBasic... it was just the intellectual challenge to find something simpler than MASM's handling of RECORDs :bg

> I'll probably never use it myself

Remember you can use it in parallel:
include \masm32\MasmBasic\MasmBasic.inc
; include \masm32\include\masm32rt.inc

Especially the deb macro is in most cases a much better alternative for bug chasing than OllyDbg. I use deb 4 (=to console) and deb 5 (=to logfile) for developing all the time, it saves me many hours of work. Or, another example, deb 6 and higher writes to console inside a loop for the first n iterations:

Quoteinclude \masm32\MasmBasic\MasmBasic.inc
   Init
   xor ecx, ecx
   mov eax, -100
   .Repeat
      deb 6, "Looping", ecx, eax   ; print ecx & eax to console for the first 6 iterations of the loop
      inc ecx
      mul ecx
   .Until ecx>1000000
   Inkey "bye"
   Exit
end start

Output:
Looping
ecx             1
eax             -100

Looping
ecx             2
eax             -200
...
Looping
ecx             6
eax             -72000
bye


EDIT: Just realised that deb 6 and higher (the one that does n loops and then stops) skipped the first loop. It's called a bug :red
Version MasmBasic6October2011b.zip (here) is ok.

ToutEnMasm


extracting bit field with the declare i posted,for example:
Quote
cpu_rflags_IOPL     equ   11b SHL 12
and eax,cpu_rflags_IOPL
shr eax,12           ;Why 12 ??? it's  a difficult question  :bdg

drizz

Quote from: minor28 on September 26, 2011, 07:38:33 AM
Thanks for your answer.

I have tryed that. It is compiled OK but not

mov MYSTRUCT.xyz,101111111110000000001111100000b
mov MYSTRUCT.xyz,-1

it returns "error A2006: undefined symbol"

http://www.masm32.com/board/index.php?topic=13386.msg104286#msg104286
Use "mask, and, or, shl, shr". If you think C/C++ does it without "and, or, shl, shr" - think/disassemble again.


Quote from: minor28 on September 26, 2011, 07:38:33 AM
And how do I define this structure
h2incx CorHdr.h
The truth cannot be learned ... it can only be recognized.