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?
No, both .data and .data? are read/write.
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.
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
Could we see more of your source to help determining the problem?
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:
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 (https://www.jj2007.eu/Masm32_Tips_Tricks_and_Traps.htm)
* 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
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 ...
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.
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 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.
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.
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:)
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