News:

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

Defining a string size

Started by lonewolff, March 01, 2009, 09:13:34 AM

Previous topic - Next topic

lonewolff

Probably a simple question, but how do you define a buffer size similar to the C++ equivalent below?

char[1024];

Thanks in advance  :bg

ecube

buffername db 1024 dup(?) make sure you don't do buffername db 1024 dup(0) as that adds to your pe files actual size, instead of just memory.

can do buffername byte 1024 dup(?) too, is same thing.

jj2007

Inside procedures, you can declare a local buffer. See \masm32\examples\exampl01\minifile\minifile.asm for an example. Search for PathBuffer inside the file.

lonewolff

Thanks for your replies.

I came across this in the MASM manual and it works ok

szBuffer   BYTE 1024 DUP(0), 0

But The following is better is it?

szBuffer 1024 dup(?)

Using that latter, I would have to initialize it to zero wouldn't I?

ecube

.data?
buff byte 1024 dup(?)is unitalized data and is automatically empty, doesn't add size to your exe,dll etc on disk...

.data
buff byte 1024 dup(0) is initalized data and will make your exe,dll etc 1024 bytes larger on the disk

if you define it locally in a procedure on the stack like

copystring proc param1:DWORD
LOCAL buff[1024]:BYTE  <--this needs to be cleared with 0's as lot of times will contain random garbage

invoke RtlZeroMemory,addr buff,1024 <--zeros the buff
ret
copystring endp

keep in mind you can only define so much data on the stack for a procedure before it'll mess up your program(make it just silently exit) from stack overflow, theres a stackprobe macro on this forum that fixes this issue

;this will stack overflow your program
copystring proc param1:DWORD
LOCAL buff[1024]:BYTE  <--this needs to be cleared with 0's as lot of times will contain random garbage
LOCAL buff1[1024]:BYTE
LOCAL buff2[1024]:BYTE
LOCAL buff3[1024]:BYTE
LOCAL buff4[1024]:BYTE
LOCAL buff5[1024]:BYTE
LOCAL buff6[1024]:BYTE
LOCAL buff7[1024]:BYTE
LOCAL buff8[1024]:BYTE
LOCAL buff9[1024]:BYTE
LOCAL buff109[1024]:BYTE
invoke RtlZeroMemory,addr buff,1024 <--zeros the buff
ret
copystring endp

lonewolff

Quote from: E^cube on March 01, 2009, 09:47:19 AM
.data?
buff byte 1024 dup(?)is unitalized data and is automatically empty, doesn't add size to your exe,dll etc on disk...

So, for program compact-ness, this looks like the way to go. And no garbage as a result if I understand correctly.

Thanks for the info! :bg

donkey

Hi lonewolf,

The only issue with initializing buffers in the .DATA or .DATA? section is if you're using MASM there is a known bug when declaring very large blocks of data, I prefer the stack for any data that is not persistent or the .CONST section if it is fixed. For strings, since the size would rarely exceed 4166 Bytes (maximum url length in unicode) its not really much of an issue. By the way you can change the size of the stack...

/stacksize xxxx for GoLink

.STACK xxxx for MASM (as a directive after .MODEL)
or
/STACK xxxx for link.exe

Edgar
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

jj2007

#7
Quote from: donkey on March 02, 2009, 08:44:16 AM
if you're using MASM there is a known bug when declaring very large blocks of data

That bug is tricky indeed. Allocating reasonable amounts is no problem, but Masm takes a looong time for data like this:
.data?
MyBuf dd 280000 dup (?) ; 2 seconds for 200k, 6 for 250k, 12 for 280k ...

If you go over 300k, masm will appear to hang. The behaviour is exponential, and linked to the dup macro. But there is a simple workaround using the ORG directive. Full example below.

include \masm32\include\masm32rt.inc

crtbuf MACRO NameOfVar, BufLen
LOCAL lbl
.data?
  align 4
  lbl LABEL byte
  ORG $+BufLen-1
  db ?
  .data
NameOfVar dd lbl ;; define it in the data section
  .code
ENDM

.code

start:
crtbuf MyFatBuffer, 10000000 ; 10 MB
invoke lstrcpy, MyFatBuffer, chr$("Howdy") ; test it - copy a string
MsgBox 0, MyFatBuffer, "crtbuf macro:", MB_OK ; and show it
exit
end start

Mark Jones

#8
Also note that for constants, many times an EQUate will work instead. Equates are assemble-time only values, and are not stored in the executable for use at run-time. i.e.


equDialogControl  EQU  1001
.code
    invoke GetDlgItemText,[hMyDialog],equDialogControl,addr myStringResult,255
...


Here, "equDialogControl" is replaced with the value 1001 prior to assembly. Math may also be performed on these values prior to assembly, such as equDialogControl + 3 and similar. Just remember that the math is carried out before the assembly, and the assembled result is then a static value. (This is not the proper method to use if the code is say, putting a variable number of controls on the application at run-time. In that case, an actual memory variable is required to keep track of how many controls are to be displayed.)

Edit: Typo.
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

tetsu-jp

looks a bit creepy to me, I've always used memory allocation via OS functions, and then load the data from files.

Rainstorm

hi,
Just approximately, how much data can be defined on the stack for a proc before there is a stack overflow ?

t  y

ecube

pretty sure its 4096 by default unless you change the stack size with the switch mentioned above, I recommend you use this macro as it cures all problems

StackProbe.inc

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
; MASM Stack Probing PROLOGUE macro
; by chep, 2005/06/22
;
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
; Allows a procedure to safely use LOCAL variables with a total size of 4kb or more,
; using an unrolled stack probing method.
;
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
; Usage:
;
;   OPTION PROLOGUE:STACKPROBE
;   MyProcedure PROC ; ...
;     ; ...
;   MyProcedure ENDP
;   OPTION PROLOGUE:PROLOGUEDEF
;
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
; Notes:
;   - When the total size of the LOCAL variables is less than 4kb, the code generated is
;     identical to PROLOGUEDEF, so there is no drawback using this macro
;   - See "OPTION PROLOGUE" and "PROC" topics in MASM32.HLP for the macro specifications
;
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
; Limitations compared to PROLOGUEDEF:
;   - Stack probing is relevant only for Windows, ie FLAT model, so it won't accept other models
;   - Due to the FLAT model restriction, LOADDS is not supported
;   - FORCEFRAME argument doesn't generate a correct epilogue when no LOCAL variables are defined
;     So it is not supported for now :(
;
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
; TODO:
;   - Allow looped probing additionally to the current unrolled probing
;     This behaviour should be controlled through macro arguments
;
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

STACKPROBE MACRO procname, flags, argbytes, localbytes, reglist, userparms:VARARG
  LOCAL parm, reg, probe, max_probe, line, page_size
  ;; Memory page size, can be changed for other architectures
  page_size = 4096
  ;; Throw an error if not in FLAT model, because stack probing is irrelevant otherwise
  IF @Model NE 7
    line TEXTEQU %@Line
    % ECHO @FileCur(line) : STACKPROBE prologue ERROR: stack probing is irrelevant if not using FLAT model
    .ERR
    EXITM <1>
  ENDIF
  ;; Detect macro arguments to give a warning
  IFNB <userparms>
    FOR parm,<userparms>
      line TEXTEQU %@Line
      % ECHO @FileCur(line) : STACKPROBE prologue warning: unknown prologue argument : parm
    ENDM
  ENDIF

  ;; Set up stack frame
  IF localbytes GT 0
    push ebp
    mov  ebp, esp
    IF localbytes LT page_size
      ;; Normal stack frame, no probing
      add  esp, (NOT localbytes)+1
    ELSE
      ;; Unrolled stack probing
      max_probe = (localbytes+page_size-1) AND (-page_size) ;; round up to next page size
      probe = page_size
      WHILE probe LE max_probe
        ;; Probe stack
        mov  DWORD PTR [ebp-probe], eax
        probe = probe + page_size
      ENDM
      add  esp, (-localbytes)
    ENDIF
  ELSEIF argbytes GT 0
    push ebp
    mov  ebp, esp
  ENDIF

  ;; USES clause
  IFNB <reglist>
    FOR reg,reglist
      push reg
    ENDM
  ENDIF

  EXITM <0>
ENDM


jj2007

Quote from: Rainstorm on April 01, 2009, 07:16:29 AM
hi,
Just approximately, how much data can be defined on the stack for a proc before there is a stack overflow ?

t  y

4096 bytes, the size of a page. You can rely on it - as Raymond Chen puts it (The Old New Thing), "Note that changing the page size creates all sorts of problems for compatibility. There are large numbers of programs out there that blindly assume that the page size is 4K. Boy are they in for a surprise."

Now the question is whether you can blindly assume that Microsoft will not surprise large numbers of programmers :wink

.data
info SYSTEM_INFO <0>
...
.code

start:
invoke GetSystemInfo, addr info
mov eax, info.dwPageSize


MichaelW

As far as I know you can use stack space in any size chunks until you approach the stack committed size (1MB?). It is when using stack space between the committed size and the reserved size (2MB?) that you must avoid accessing past the guard page.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

cnt equ 1036213       ;1048576=1MB

biglocals proc
  LOCAL smp[cnt]:BYTE
  lea edx, smp
  mov ecx, cnt
  .WHILE ecx
    mov [edx+ecx], cl
    dec ecx
  .ENDW
  ret
biglocals endp
 
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    call biglocals
    inkey "Press any key to exit..."
    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start

eschew obfuscation

jj2007

#14
Quote from: MichaelW on April 01, 2009, 02:53:16 PM
As far as I know you can use stack space in any size chunks until you approach the stack committed size (1MB?). It is when using stack space between the committed size and the reserved size (2MB?) that you must avoid accessing past the guard page.

I had written a similar test some time ago, but it crashes at 4096 bytes with an access violation. Are we talking about the same phenomenon?

EDIT: It seems it works also for 8192 bytes:
Quotemov eax, info.dwPageSize
   add eax, eax
   mov s4096, eax
But it crashes neatly at 16384 12212 bytes. New code attached shows why: Apparently the OS allocates three pages, 4096*3 = 12288 bytes. A few have been used for other purposes. For 12212 bytes allocated, first access is at 0012D000, i.e. a page boundary; for 12214 bytes it is 2 bytes below and bang there is the access violation.

[attachment deleted by admin]