News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Win32 API: PHYSICALDRIVE, READFILE, ERROR_INVALID_PARAMETER, memory alignment

Started by MtheK, July 21, 2013, 01:21:47 AM

Previous topic - Next topic

MtheK

  I made a macro for this, except using the IBM formula until/if ORG works in .CODE:

$ALIGN   MACRO ALIGNSIZE
         LOCAL $ALIGNS,$ALIGNZ,$ALIGNE,$ALIGNQ,$ALIGNX

  IF           ALIGNSIZE GT 0

    IFDIFI     @CurSeg,<_TEXT>
$ALIGNS  BYTE  0 DUP(00h)          ; show begin LOC CTR
    ELSE
         JMP   $ALIGNQ             ; branch around alignment & show LOC CTR
    ENDIF

    IF         ($ - @CurSeg) EQ 0
$ALIGNZ  EQU   $ - @CurSeg         ; already at start of segment, so can't do or get extra
    ELSE
         BYTE  ((((($ - @CurSeg)-1)/ALIGNSIZE)*ALIGNSIZE)+ALIGNSIZE-($ - @CurSeg)) DUP(00h)
    ENDIF

    IFDIFI     @CurSeg,<_TEXT>
$ALIGNE  BYTE  0 DUP(00h)          ; show end   LOC CTR
    ELSE
$ALIGNQ:                           ; get past alignment & show LOC CTR
    ENDIF

  ELSE
$ALIGNX  EQU   $ - @CurSeg         ; size not valid
  ENDIF
         ENDM


To use it, just code the following in .DATA and/or .CODE:
         $ALIGN 4096
In this case, it aligns to 4K. Any number can be used. I assembled OK to 65536 (64K). For .CODE, a JMP is generated to branch around it.


jj2007

How did you test your macro? For my attached example, it doesn't work properly :(
It assembles fine, but instead of aligning, it just adds 100h to the current $:
004043E0        v1 (.data?, dd)
004044E0        v1a

The only method that works for me so far is creating a new segment.

MtheK

  That's weird; this is what I get:

00000000         .data?
00000000 00000000      v1   dd ?
            $ALIGN MySize
00000004           1   ??0019  BYTE  0 DUP(00h)          ; show begin LOC CTR
00000004  000000FC [        1            BYTE  ((((($ - @CurSeg)-1)/MySize)*MySize)+MySize-($ - @CurSeg)) DUP(00h)
       00
      ]
ALIGNX.ASM(63) : warning A4014: instructions and initialized data not supported in BSS segments
$ALIGN(12): Macro Called From
  ALIGNX.ASM(63): Main Line Code
00000100           1   ??001B  BYTE  0 DUP(00h)          ; show end   LOC CTR
00000100 00000000      v1a   dd ?

It seems like 'v1a' is aligned, at least assembly-wise? Could this BSS segment not be aligned by the OS at run time? I do assume that the OS does this. For .DATA and .CODE, they are aligned by the OS for me...


MichaelW

I didn't spend much time examining the details, but in my test the alignment function appears to work, as it should.

;========================================================================================
$ALIGN  MACRO ALIGNSIZE
  LOCAL $ALIGNS,$ALIGNZ,$ALIGNE,$ALIGNQ,$ALIGNX
  IF ALIGNSIZE GT 0
    IFDIFI @CurSeg,<_TEXT>
      $ALIGNS BYTE 0 DUP(00h)     ; show begin LOC CTR
    ELSE
      JMP $ALIGNQ                 ; branch around alignment & show LOC CTR
    ENDIF
    IF ($ - @CurSeg) EQ 0
      $ALIGNZ EQU $ - @CurSeg  ; already at start of segment, so can't do or get extra
    ELSE
      BYTE ((((($ - @CurSeg)-1)/ALIGNSIZE)*ALIGNSIZE)+ALIGNSIZE-($ - @CurSeg)) DUP(00h)
    ENDIF
    IFDIFI @CurSeg,<_TEXT>
      $ALIGNE BYTE 0 DUP(00h)   ; show end LOC CTR
    ELSE
      $ALIGNQ:                    ; get past alignment & show LOC CTR
    ENDIF
  ELSE
    $ALIGNX EQU $ - @CurSeg         ; size not valid
  ENDIF
ENDM
;========================================================================================
;----------------------------------------
; Returns the maximum alignment of _ptr.
;----------------------------------------
alignment MACRO _ptr
    push ecx
    xor eax, eax
    mov ecx, _ptr
    bsf ecx, ecx
    jz @F
    mov eax, 1
    shl eax, cl
  @@:
    pop ecx
    EXITM <eax>
ENDM
;========================================================================================
    include \masm32\include\masm32rt.inc
;========================================================================================
    .data
        db 0
        FOR arg,<1,2,3,4,5,6,7,8,16,32,64,128,256>
            db 0
            $ALIGN arg
            D&arg db 0
        ENDM
    .code
;========================================================================================
start:
;========================================================================================
    FOR arg,<1,2,3,4,5,6,7,8,16,32,64,128,256>
        printf("data %d  %d\n", arg, alignment(OFFSET D&arg))
    ENDM

    printf("\n")

    ;---------------------------------------------------------
    ; Some arg values > 128 will trigger an error:
    ; error A2075: jump destination too far : by xxx byte(s)
    ; Where the value of xxx varies.
    ;---------------------------------------------------------

    FOR arg,<1,2,3,4,5,6,7,8,16,32,64,128>
        $ALIGN arg
        C&arg:
    ENDM

    FOR arg,<1,2,3,4,5,6,7,8,16,32,64,128>
        printf("code %d  %d\n", arg, alignment(C&arg))
    ENDM

    inkey
    exit
;========================================================================================
end start


data 1  2
data 2  4
data 3  2
data 4  8
data 5  2
data 6  4
data 7  2
data 8  16
data 16  32
data 32  64
data 64  128
data 128  256
data 256  512

code 1  4
code 2  2
code 3  2
code 4  4
code 5  2
code 6  2
code 7  1
code 8  32
code 16  16
code 32  64
code 64  128
code 128  256


MtheK,

Enclosing your code in code tags will preserve the formatting.
Well Microsoft, here's another nice mess you've gotten us into.

MtheK

"code tags"...u mean that 'insert code' # button? I tried that, let's see if it works...

  I changed the 3 DUP(00h) to DUP(?) to eliminate that error msg in BSS:



00000000         .data?
00000000 00000000      v1   dd ?
            $ALIGN MySize
00000004           1   ??0019  BYTE  0 DUP(?)          ; show begin LOC CTR
00000004  000000FC [        1            BYTE  ((((($ - @CurSeg)-1)/MySize)*MySize)+MySize-($ - @CurSeg)) DUP(?)
       00
      ]
00000100           1   ??001B  BYTE  0 DUP(?)          ; show end   LOC CTR
00000100 00000000      v1a   dd ?


jj2007

The problem is really that "$" refers to an assembly-time situation that will be changed by the linker. Run the code below with Olly, and watch what happens if you eliminate the .data section. As it stands, you can see this in Olly:
<ModuleEn /$  B8 10204000   mov eax, offset 00402010
00401005  |.  B9 10304000   mov ecx, offset 00403010

... and, data dump in in the lower left corner:
00402000  78 56 34 12|00 00 00 00|00 00 00 00|00 00 00 00|
00402010  00 00 00 00|00 00 00 00|00 00 00 00|00 00 00 00|

include \masm32\include\masm32rt.inc

;========================================================================================
$ALIGN  MACRO ALIGNSIZE
  LOCAL $ALIGNS,$ALIGNZ,$ALIGNE,$ALIGNQ,$ALIGNX
  IF ALIGNSIZE GT 0
    IFDIFI @CurSeg,<_TEXT>
      $ALIGNS BYTE 0 DUP(00h)     ; show begin LOC CTR
    ELSE
      JMP $ALIGNQ                 ; branch around alignment & show LOC CTR
    ENDIF
    IF ($ - @CurSeg) EQ 0
      $ALIGNZ EQU $ - @CurSeg  ; already at start of segment, so can't do or get extra
    ELSE
      BYTE ((((($ - @CurSeg)-1)/ALIGNSIZE)*ALIGNSIZE)+ALIGNSIZE-($ - @CurSeg)) DUP(00h)
    ENDIF
    IFDIFI @CurSeg,<_TEXT>
      $ALIGNE BYTE 0 DUP(00h)   ; show end LOC CTR
    ELSE
      $ALIGNQ:                    ; get past alignment & show LOC CTR
    ENDIF
  ELSE
    $ALIGNX EQU $ - @CurSeg         ; size not valid
  ENDIF
ENDM
;========================================================================================

.data?
v_uid dd ?
$ALIGN 4096
v_uidA dd ?

.data
v_id dd 12345678h

.code
start: mov eax, offset v_uid
mov ecx, offset v_uidA
ret

end start

MichaelW

When you click the Insert Code (#) button you get a start tag and an end tag. The code needs to be inserted between the start tag and the end tag.

http://en.wikipedia.org/wiki/BBCode
Well Microsoft, here's another nice mess you've gotten us into.

MtheK

  OK, got it; testing..:


$ALIGN  MACRO ALIGNSIZE
  LOCAL $ALIGNS,$ALIGNZ,$ALIGNE,$ALIGNQ,$ALIGNX
  IF ALIGNSIZE GT 0
    IFDIFI @CurSeg,<_TEXT>
      $ALIGNS BYTE 0 DUP(?)     ; show begin LOC CTR
    ELSE
      JMP $ALIGNQ                 ; branch around alignment & show LOC CTR
    ENDIF
    IF ($ - @CurSeg) EQ 0
      $ALIGNZ EQU $ - @CurSeg  ; already at start of segment, so can't do or get extra
    ELSE
      BYTE ((((($ - @CurSeg)-1)/ALIGNSIZE)*ALIGNSIZE)+ALIGNSIZE-($ - @CurSeg)) DUP(?)
    ENDIF
    IFDIFI @CurSeg,<_TEXT>
      $ALIGNE BYTE 0 DUP(?)   ; show end LOC CTR
    ELSE
      $ALIGNQ:                    ; get past alignment & show LOC CTR
    ENDIF
  ELSE
    $ALIGNX EQU $ - @CurSeg         ; size not valid
  ENDIF
ENDM


-----

  Ah, I see; the linker controls the alignment:

ALIGNX2

Timestamp is 51f69844 (Mon Jul 29 10:28:52 2013)

Preferred load address is 00400000

Start         Length     Name                   Class
0001:00000000 0000101bH .text                   CODE
0002:00000000 00000164H .rdata                  DATA
0002:00000164 00000000H .edata                  DATA
0003:00000000 00000104H .data                   DATA
0003:00000104 00001338H .bss                    DATA

WinDbg shows v_uid at 0x00404104, kinda like the linker says above for .bss,
so, yea, I only then work for segments that start with 0 per the linker,
a la .text (.CODE) and .data (all I've ever used), and, I guess, .rdata.

MtheK

  FYI: A file opened with the WINAPI CreateFile and FILE_FLAG_NO_BUFFERING,
and using a ReadFile and/or WriteFile, requires the buffer(s) to be aligned,
where SetEndOfFile does not; perfect for my $ALIGN macro. In my case,
I use this to ensure there is no caching, even with EXCLUSIVE. Kinda like
an IBM M/F VSAM SHAREOPTIONS(4,4), which requires ENQ/DEQ logic; this logic
is not a performance concern as it does minimum I/O (just btx calls in a .BAT),
but requires absolute control of current data w/no outside interference.
I also couldn't read/write a single byte w/o that ERROR_INVALID_PARAMETER
rc occuring; I think the minimum is a physical sector, so I used a multiple
of 512 (in my case, a 4K page) and just padded the rest w/nulls.


MtheK

  FYI: As I learned how to use .data?, I realized that if I prefix it with
an '$ALIGN 4096', since it follows .data which IS page-aligned, then .data?
should also be page-aligned, as, for example, shown by a .map:

0003:00000000 00004000H .data                   DATA
0003:00004000 00003400H .bss                    DATA

so that's cool.