News:

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

Main Menu

Dumb question regarding data segment (.data)

Started by NoCforMe, July 12, 2022, 12:13:45 PM

Previous topic - Next topic

NoCforMe

Dumb, because I've been writing Win32 programs in assembly language for years and only just ran into this problem now.

I have a variable in my data segment, defined with .data, and I'm getting an access violation error trying to write data to it.

Variable is defined as

Q2Abuffer DB "01234567890123456789",0 ;20 ASCII digits


(This is used in a QWORD-to-ASCII converter.)

In fact, I get the violation error trying to write anywhere in my .data segment.

I guess I've always unconsciously used that segment for read-only variables, and put all the ones I want to write to into the .data? segment. But I never realized until now that the .data segment was read-only. Is it? If so, is there any way to change this behavior with a flag or directive or something?
Assembly language programming should be fun. That's why I do it.

hutch--


NoCforMe

Now I really cannot figure out why I'm getting access violations any time I try to write there. I can see in OllyDebug where I am, and it hits me every time.
Assembly language programming should be fun. That's why I do it.

hutch--

Straight masm32.

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

comment * -----------------------------------------------------
                        Build this  template with
                       "CONSOLE ASSEMBLE AND LINK"
        ----------------------------------------------------- *

    .data?
      value dd ?

    .data
      item dd 0
      pval dd value     ; get pointer
      pitm dd item      ; get pointer

    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main
    inkey
    exit

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

main proc

    mov pval, 1234
    mov pitm, 5678

    print str$(pval),13,10
    print str$(pitm),13,10

    ret

main endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end start

quarantined

Could we see more of your source to help determining the problem?

NoCforMe

Wellllll, I'll try. Like they say, it's complicated (my code). I'll try to post some relevant snippets.

My data section:

;============================================
; HERE BE DATA
;============================================
.data

..... some stuff .....

NoSelectedFolderMsg DB "No folder selected. Use the Browse button to choose one.", 0
EmptyFindFieldMsg DB "Nothing to find! Type some text in the ""Find"" field.", 0
SearchTermErrorMsg DB "Illegal character (<>*?+/\:|) in find specifier.", 0
NoFilesFoundMsg DB "No files found.", 0
NomoFilesMsg DB "No mo' files.", 0

Q2Abuffer DB "01234567890123456789",0 ;20 ASCII digits

FileCountFmt DB "%s files found", 0
NoFilesMsg DB "No files found", 0
FileDateFmt DB "%u/%u/%u, %u:%02u %s", 0
AMstr DB "am", 0
PMstr DB "pm", 0

..... some more stuff .....


The code that's causing the access violation:

;====================================================================
; Convert 64-bit unsigned integer (QWORD) to ASCII decimal string
;
; On entry,
; EDX:EAX = QWORD value to convert
;
; Returns:
; EAX--> buffer containing numeric string
;====================================================================
Q2A PROC

PUSH EBX
PUSH ESI
PUSH EDI

; STD ;No, not a venereal disease:
;set direction flag to go backwards.
MOV EDI, OFFSET Q2Abuffer + 18 ;Start @ end.
MOV ECX, EDX
XCHG EAX, ESI
MOV EBX, 100 ;Load with divisor.

qloop: XOR EDX, EDX
XCHG EAX, ECX
DIV EBX
XCHG EAX, ECX
XCHG EAX, ESI
DIV EBX
XCHG EAX, ESI
XCHG EAX, EDX
AAM
XCHG AL, AH ;Swap bytes.
OR AX, 3030h ;Convert to ASCII.
; STOSW ;Store 2 digits.
mov [edi], ax
sub edi, 2
MOV EAX, ECX
OR EAX, ESI
JNZ qloop

ADD EDI, 2
; CLD ;Be sure to clear direction flag!
CMP BYTE PTR [EDI], '0' ;Leading zero?
JNE exit99 ;  No, done.

INC EDI ;  Yep, increment past it.
exit99: MOV EAX, EDI ;Return with pointer to buffer.
POP EDI
POP ESI
POP EBX
RET

Q2A ENDP

As soon as I access that item (Q2Abuffer) with mov [edi], ax, bam! access violation writing to it. WTF????

If I move that item to my data? section, it works OK.

You'll notice I modified that code (which I just downloaded from here today) to not use the string instruction STOSW. The routine works fine, BTW (so long as there aren't any access violations!).

If it matters, the order of my sections is:
  • .data
  • .data?
  • .code
Assembly language programming should be fun. That's why I do it.

jj2007

Quote from: hutch-- on July 12, 2022, 12:16:36 PM
No, both .data and .data? are read/write.

Exactly.

Quote- Last but not least: A few Rules for the Forum

* Use include \masm32\include\masm32rt.inc, not include C:\masm32\include\masm32rt.inc; many people have installed Masm32 on a different drive, and it's a real nuisance having to replace C: with D: to test a code snippet

* To allow others to test your code, do not use environment variables for your paths. Masm32 has a hard-coded path structure, for good reasons.

* Post your complete code. Some believe that older members are eager to construct the missing headers around your snippets, but this belief is FALSE

NoCforMe

Well, I seem to have fixed the problem. Trouble is, I have no idea why what I did fixed it.

If you read that other thread here about WM_xxxx message mapping, I had a pretty big include file in that data section, with strings and a big table for every WM_xxxx message. When I took it out I stopped getting access violations writing to items there.

Now I just have to figure out why ... ah, the mysteries of programming ...
Assembly language programming should be fun. That's why I do it.

NoCforMe

OK, mystery solved. And of course it was because of a dumb mistake I made.

My include file started with a .data statement. Find, good. Lots of data. But at the end I opened a .code section with a small subroutine. But I never went back to .data, so all subsequent data ... was going into a code segment. No wonder I got access violations; you're not supposed to write to code segments*. Duh.

Pays to actually look at your own files once in a while, I guess.

* Of course there are ways of doing that, for self-modifying code, etc., but not anything I want to mess with here.
Assembly language programming should be fun. That's why I do it.

jj2007

Quote from: NoCforMe on July 12, 2022, 06:27:45 PM
OK, mystery solved. And of course it was because of a dumb mistake I made.

My include file started with a .data statement. Find, good. Lots of data. But at the end I opened a .code section with a small subroutine. But I never went back to .data, so all subsequent data ... was going into a code segment. No wonder I got access violations; you're not supposed to write to code segments*.

You are touching another religious issue: using include files. There is no debate about Windows.inc & friends, of course:

include \masm32\include\masm32rt.inc
.code
start:
  MsgBox 0, "How are you?", "Hello World:", MB_OK
  exit
end start


This include, masm32rt.inc, is essential. But some people here post archives with 20 little files, and then wonder why other members didn't notice that in file #17 there was a wrong PROTO... if I see such archives, I simply ignore the post.

With a reasonable editor, there is no need to split a project in a dozen little includes. Just keep it in one fat file, and you'll see immediately that you didn't go back to .data :cool:

hutch--

I confess I regularly add .DATA sections in code if I want a string to be close to where I call it. Its a bad habit but it works well.

.data
  item db "12345678",0
  pitm dd item
.code

It just means I don't have to go look it up in an include file.

jj2007

I do that during development, Hutch. When it's done, I move the .data above the proc and, if read only, omit the .data thus leaving it in the .code section. Alternatively, I just use invoke somealgo, chr$("my string") - it's the most readable way to do it.

NoCforMe

Quote from: jj2007 on July 12, 2022, 06:35:51 PM
Quote from: NoCforMe on July 12, 2022, 06:27:45 PM
OK, mystery solved. And of course it was because of a dumb mistake I made.

My include file started with a .data statement. Find, good. Lots of data. But at the end I opened a .code section with a small subroutine. But I never went back to .data, so all subsequent data ... was going into a code segment. No wonder I got access violations; you're not supposed to write to code segments*.

You are touching another religious issue: using include files. There is no debate about Windows.inc & friends, of course:

include \masm32\include\masm32rt.inc
.code
start:
  MsgBox 0, "How are you?", "Hello World:", MB_OK
  exit
end start


This include, masm32rt.inc, is essential. But some people here post archives with 20 little files, and then wonder why other members didn't notice that in file #17 there was a wrong PROTO... if I see such archives, I simply ignore the post.

With a reasonable editor, there is no need to split a project in a dozen little includes. Just keep it in one fat file, and you'll see immediately that you didn't go back to .data :cool:

I think in general your advice here is good. Reduce include files to a necessary minimum, like just header files for common shared subroutines. I have one large project where the main .asm file includes 5 more .asm files near the end, most of which contain only code. It's a good way to keep the size of each "module" (they're not really that, just related code) manageable; the largest of them is 228 Kb.

Oddly enough, even though I like using a good editor, I've ended up using just ... Notepad for all my editing. Yes, primitive, but it is reliable--I've never once seen it crash or even screw up--and it gets the job done. (Back in the day when I was writing a lot of DOS 16-bit stuff I latched onto MultiEdit, which I loved: it was extensible, configurable, used macros, etc. But it won't run anymore under Windoze.  :sad:)
Assembly language programming should be fun. That's why I do it.

daydreamer

Quote from: jj2007 on July 12, 2022, 07:26:00 PM
I do that during development, Hutch. When it's done, I move the .data above the proc and, if read only, omit the .data thus leaving it in the .code section. Alternatively, I just use invoke somealgo, chr$("my string") - it's the most readable way to do it.
I prefer this macro style
invoke apicall,chr$("string1),chr$("string2"),ustr$(dword)
Over more kinda c style :
.data
String1 db "string1",0
String2 db "string2",0
__________________________
Loads of scrolldown to proc placed almost last in source file that uses the above strings

I am Reusing separate .inc file for gui code when making windows program
I use qeditor mostly

my none asm creations
https://masm32.com/board/index.php?topic=6937.msg74303#msg74303
I am an Invoker
"An Invoker is a mage who specializes in the manipulation of raw and elemental energies."
Like SIMD coding