0

So I’ve been writing this program that should take an array of pointers of a custom struct (DbRecord). My code is currently set up to hold 512 different pointers to DbRecord structs. I’ve been attempting to write a function readArray that will iterate through the pointers and print out the full contents of the DbRecords. As can be seen in the code, I am using the windows console api. The problem is I can’t figure out how to write the function, I have a picture in my mind as too the pointers as the array elements and then possibly using an offset to access the fields in the struct. One of my attempts involved a LEA to add the offset to the address of the current element, but the LEA did not behave as I expected.

Here is the code, I took out the different attempts because it was turning in too a mess:

.386
.model flat, stdcall
option casemap :none

include windows.inc
include user32.inc
include kernel32.inc

addElement PROTO: ptr DbRecord
readArray PROTO

.data?
    DbRecord struct
        Id      dd  ?
        WordOne     db 32   dup(?) ; db is define byte, set value of byte
        WordTwo     db 32   dup(?)
        WordThree   db 32   dup(?)
        Year        dd  ?
    DbRecord ends

    array dword 512 dup(?)      ; pointer in memory to start of array
;   newElementPointer DbRecord <>
    hStdOut dd ?
    bytesWritten dd ?

.data
    arrayCount dd 0
    hello db 'Hello World!', 0

.code
main proc
    LOCAL DbRecord01:DbRecord
    LOCAL DbRecord02:DbRecord
    mov [DbRecord01.Id], 1;

    ; any other way than one character at a time?
    mov byte ptr [DbRecord01.WordOne], 'D'
    mov byte ptr [DbRecord01.WordOne + 1], 'o'
    mov byte ptr [DbRecord01.WordOne + 2], 'g'
    mov byte ptr [DbRecord01.WordOne + 3], 0

    mov byte ptr [DbRecord01.WordTwo], 'C'
    mov byte ptr [DbRecord01.WordTwo + 1], 'a'
    mov byte ptr [DbRecord01.WordTwo + 2], 't'
    mov byte ptr [DbRecord01.WordTwo + 3], 0

    mov byte ptr [DbRecord01.WordThree], 'E'
    mov byte ptr [DbRecord01.WordThree + 1], 'y'
    mov byte ptr [DbRecord01.WordThree + 2], 'e'
    mov byte ptr [DbRecord01.WordThree + 3], 0
    mov [DbRecord01.Year], 2022;

    mov [DbRecord02.Id], 2;

    ; any other way than one character at a time?
    mov byte ptr [DbRecord02.WordOne], 'c'
    mov byte ptr [DbRecord02.WordOne + 1], 'a'
    mov byte ptr [DbRecord02.WordOne + 2], 'r'
    mov byte ptr [DbRecord02.WordOne + 3], 0

    mov byte ptr [DbRecord02.WordTwo], 'H'
    mov byte ptr [DbRecord02.WordTwo + 1], 'o'
    mov byte ptr [DbRecord02.WordTwo + 2], 'u'
    mov byte ptr [DbRecord02.WordTwo + 3], 's'
    mov byte ptr [DbRecord02.WordTwo + 3], 'e'
    mov byte ptr [DbRecord02.WordTwo + 3], 0

    mov byte ptr [DbRecord02.WordThree], 'W'
    mov byte ptr [DbRecord02.WordThree + 1], 'i'
    mov byte ptr [DbRecord02.WordThree + 2], 'n'
    mov byte ptr [DbRecord02.WordThree + 3], 'd'
    mov byte ptr [DbRecord02.WordThree + 4], 'o'
    mov byte ptr [DbRecord02.WordThree + 5], 'w'
    mov byte ptr [DbRecord02.WordThree + 6], 's'
    mov byte ptr [DbRecord02.WordThree + 7], 0

    mov [DbRecord02.Year], 2002;
        
    invoke GetStdHandle, STD_OUTPUT_HANDLE
    mov [hStdOut], eax

    invoke WriteConsole, hStdOut, offset hello, sizeof hello, offset bytesWritten, NULL
    invoke addElement, addr DbRecord01
    invoke addElement, addr DbRecord02
    invoke readArray

    ret
main endp

addElement proc uses edx DbRecordPointer: ptr DbRecord
    Local newElementPointer: Dword
    invoke VirtualAlloc, NULL, sizeof DbRecord, MEM_COMMIT, PAGE_READWRITE
    mov newElementPointer, eax
    invoke RtlMoveMemory, eax , DbRecordPointer, sizeof DbRecord
    mov edx, arrayCount
    mov dword ptr  [array +4*edx], eax
    inc edx
    mov arrayCount, edx

    ret
addElement endp


readArray proc

    ret
readArray endp



end main



debugging_info

readArray proc
    local current: dword


    lea eax, [array + offset DbRecord.WordOne]
    ;.while current != 0

        invoke WriteConsole, hStdOut, eax,3, offset bytesWritten, NULL

    ;.endw

    ret
readArray endp
  • 2
    Yeah well you should add back the attempt you think most promising :) – Jester Jan 17 '23 at 15:50
  • Well, I closed my notepad++ last night and didn’t really save the attempt, I am sure I rewrite the one I spent the most time on. But in the debugger I can get this in the readArray function, so I believe things are correctly setup in memory. – Chad Botting Jan 17 '23 at 16:00
  • Multiple stores in a row to to `[DbRecord02.WordTwo + 3]` will just overwrite each other. Maybe you meant to increment the offset while copy/pasting? If you were using an assembler with more convenient syntax (NASM or I think FASM), you could write `mov dword [...], 'Hous'` to store 4 bytes with one instruction, while still keeping the code very readable for humans. You can [do the same thing with MASM](//stackoverflow.com/q/56281407), but you'd have to reverse the letters or encode ASCII to a hex integer manually, taking account of the little-endian byte order. MASM and GAS suck at this. – Peter Cordes Jan 17 '23 at 16:06
  • 1
    You're not asking us to finish your code, so, what's your question? FYI, you should work out the program in a language you know well, then take that to assembly. You need to focus on what you are given and how to make that do what you need, and worry about the assembly version after you figure this out. – Erik Eidt Jan 17 '23 at 16:08
  • Ya I notied that Hous problem and fixed it, but that is not the cause of my problems here, I just updated the post and code I posted is very similar to what I was getting at last night, but LEA does not do what I though it would do. I thought a LEA eax [array + offset.WordOne] would give 0x00110004 based on the debugger screen shot I pasted in, but it seems like it is just a garbage value. I am not sure I understand LEA – Chad Botting Jan 17 '23 at 16:17
  • 1
    Your array contains pointers. You need something like `mov eax, [array]; lea eax, [eax+offset DbRecord.WordOne]` – Jester Jan 17 '23 at 16:25
  • thanks, this seemed to help a little too: ' `readArray proc local current: dword mov ebx, offset DbRecord.WordOne add ebx, array ;.while current != 0 invoke WriteConsole, hStdOut, ebx,3, offset bytesWritten, NULL ;.endw ret readArray endp` – Chad Botting Jan 17 '23 at 16:27
  • Thanks, progress feels great, it means alot. @jester, your example seems to be working. – Chad Botting Jan 17 '23 at 16:34
  • @PeterCordes Wouldn't you have to type it backwards, i.e. `mov dword [...], 'suoH'`, or is NASM/FASM smart enough to reverse it for you? – puppydrum64 Jan 18 '23 at 11:34
  • @puppydrum64: NASM puts multi-character constants into machine code in source order so `mov dword [mem], "abcd"` produces the same thing as `db "abcd"`. Immediate operands in machine code match the order they'll be stored into data memory so NASM doesn't have to reverse anything. See [When using the MOV mnemonic to load/copy a string to a memory register in MASM, are the characters stored in reverse order?](https://stackoverflow.com/a/57439043) for example of source and disassembly from NASM for contrast with how much MASM sucks. Apparently EuroAssembler is also good; haven't tried FASM. – Peter Cordes Jan 18 '23 at 12:43
  • @PeterCordes Yeah, I keep forgetting that endianness isn't really an issue as long as you're not trying to communicate between two CPUs that have opposite endianness. The only time I've ever really had to worry about it is on the Sega Genesis or NeoGeo which have a Z80 coprocessor for sound. I always figured that's what this article was about: https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html – puppydrum64 Jan 18 '23 at 12:58

0 Answers0