0

So one of our projects has hit a snag with some assembly code that needs to be written. We have an old, old (compiled with Borland 1992) memory tester C program that occasionally needs to drop to assembly to read values from certain areas of memory. I need to write a MASM assembly routine that takes in a 32 bit memory address and return the dword at that location. My only assembly experience was about 4 years ago in MIPS, so I'm pretty rusty. So far, I have this:

; Do a direct read of a memory address
public _mmap_io
_mmap_io PROC FAR

push  bp          ; 'C' entry    

mov   bp,sp       ; set pointer to parm list
push  es
xor   ax, ax      ; clear ax        
mov   es, ax      ; clear es?
add   bp, 6       ; bump to parms

xor eax,eax       ; clear eax
mov eax, [bp]     ; move the value pointed to by bp into eax
mov esi, eax      ; source index
mov eax,es:[esi]                           

pop   es    
pop   bp          ; 'C' exit    
ret

_mmap_io ENDP

The problem is when I read in values, I get something that is almost, but not quite, what I'm looking for. When I run something like...

DWORD output = mmap_io(0xEFF87110);
printf("output: %p\n");

output = mmap_io(0xE0000000);
printf("output: %p\n");

On a memory space where 0xEFF87110 has the value 0x00000000 in it, and 0xE0000000 has 0x80863C00 in it, I end up getting:

output: 0110:0000
output: 9463:8086

I believe that I'm mixing up my 16 bit and 32 bit registers, but any attempts to fix these have resulted in further problems. Does anyone have some better, cleaner code for reading directly from a 32 bit memory address, or can help me fix my problem?

GEOCHET
  • 21,119
  • 15
  • 74
  • 98
Zach H
  • 469
  • 5
  • 18
  • Just use 32bit registers instead of 16bit. The 32bit are with the 'e' prefix. ESP EBP ESI EDI EAX EBX EDX ECX – blez Jun 01 '12 at 19:47
  • The code is 20 years old and worked for MS-DOS or Windows 2.0. Things just doesn't work that way anymore! – Bo Persson Jun 01 '12 at 20:39
  • There's not anywhere near enough information to debug this program. The assembly code you've written should crash either because it's running protected mode and you've loaded a NULL selector into ES or because you're running real mode and `0xEFF87110` exceeds the 16-bit real-mode segment limit. – Ross Ridge Nov 16 '16 at 18:36

1 Answers1

-1

This can be done in good old C. No need for assembly. Assuming that a "dword" is 32 bits:

#include <stdint.h>

uint32_t peek32(uintptr_t address)
{
   volatile uint32_t * ptr = (volatile uint32_t *)address;
   return *ptr;
}

void poke32(uintptr_t address, uint32_t value)
{
   volatile uint32_t * ptr = (volatile uint32_t *)address;
   *ptr = value;
}

Similar versions can be had for 16- and 8-bit values.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • But translating `mmap_io(0xEFF87110)` into `peek32(0xEFF87110)` will get you a nice Access Violation. To get memory mapped I/O, you need a device driver. – Bo Persson Jun 01 '12 at 20:43
  • Wait a minute. The asker says that they "drop into MASM" from C to do something that can be done without having to leave C. Why the downvote? – Kuba hasn't forgotten Monica Aug 02 '12 at 04:49
  • Just a guess, the voter doesn't know any 32-bit system where the code will actually work. Running a memory tester in virtual memory is bad on several levels. The original code is from 1992 and ran on 16-bit MS-DOS, where you actually *could* access all the memory. (See my comment on the question). – Bo Persson Aug 02 '12 at 07:03
  • 2
    The code was supposed to be a replacement for the original code. Whether it works on a random Windows box or not is tangential to the problem. My presumption is that whatever process it was running in would have access rights to the memory it was to test. There's a point where you have to stop making up complications :) – Kuba hasn't forgotten Monica Aug 03 '12 at 12:39
  • 1
    `uintptr_t` would be a better type for addresses, or maybe just `uint32_t *`. Totally agree that this does what the OP asked for, regardless of whether or not that's a stupid thing to ask for. memory-mapped I/O is literally just loads and stores. Asking the OS to map some of your virtual address space to somewhere interesting is necessary first (under OSes with memory protection, unlike DOS), but once that's done, this is what you'd use. – Peter Cordes Nov 16 '16 at 19:20
  • DWORD is x86-speak for a 32-bit value, yes. Windows API headers even define `DWORD` as a 32-bit C type. But `uint32_t` is a more portable choice. – Peter Cordes Nov 16 '16 at 20:46