News:

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

Main Menu

Display the stack and questions

Started by coder, January 27, 2017, 12:29:52 AM

Previous topic - Next topic

coder

Been practicing MASM lately. Not sure how this would work on other PCs but here is a code sample I been working on the past days. Just a simple routine to display the stack. But my urgency is about turning this kind of code into 1) an accessible .obj and 2) DLL, the native way if possible -  that works in almost all situations and using any linker possible. I still don't quite get the full picture of various linking techniques in 64-bit environment.

Just need a simple outline/layout for such conversions and other related things like the requirement for underscores, decorated names etc.

Thanks in advance.


Vortex

Hi coder,

Here is a similar example :

EXTERNDEF printf:PROC
EXTERNDEF ExitProcess:PROC

option casemap:none

.data

format      db '%.16X %.16X',13,10,0

.code

mainCRTStartup PROC

    mov     rdx,rsp
    sub     rsp,4*8+8

    mov     rcx,10
    call    DisplayStack

    xor     rcx,rcx
    call    ExitProcess

mainCRTStartup ENDP

DisplayStack PROC

LOCAL dummy:QWORD   ; copy rcx and rdx
LOCAL _rcx:QWORD    ; to aligned memory locations
LOCAL dummy2:QWORD
LOCAL _rdx:QWORD

    sub     rsp,4*8
    shl     rcx,3
    add     rdx,rcx
    mov     _rcx,rcx
    mov     _rdx,rdx
@@:
    mov     rcx,OFFSET format
    mov     r8,_rdx
    mov     rdx,QWORD PTR [r8]
    call    printf

    sub     _rdx,8
    sub     _rcx,8
    jnz     @b

    ret

DisplayStack ENDP

END


The object module has no any decorated symbols :

\PellesC\bin\podump.exe /SYMBOLS DisplayStack64.obj

Dump of DisplayStack64.obj

File type: OBJ

SYMBOL TABLE
0000 009E9D1B ABS    notype      static       | @comp.id
0001 00000000 SECT1  notype      static       | .text
     length of section   5A, #relocations    3, #linenumbers    0
0003 00000000 SECT2  notype      static       | .data
     length of section    E, #relocations    0, #linenumbers    0
0005 00000000 SECT3  notype      static       | .debug$S
     length of section   70, #relocations    0, #linenumbers    0
0007 00000000 UNDEF  notype      external     | printf
0008 00000000 UNDEF  notype      external     | ExitProcess
0009 00000000 SECT2  notype      static       | format
000A 00000000 SECT1  notype ()   external     | mainCRTStartup
000B 0000001B SECT1  notype ()   external     | DisplayStack

coder

Thanks for the alternative code Vortex. Gives me new idea on printf formatting.

On to the code, if you could make a slight adjustment to your code, you should be able to see the actual / current content of the stack instead.

push rcx
push rdx
push rbx
mov rax,10
call DisplayStack64  ;Display the 3 objects recently pushed above


The adjustment will serve the purpose of the module even more accurately.

Btw, I managed to make an accessible object (.obj) by using the "public" keyword and it is now linkable from both LINK.exe and GCC. I tried linking with GOLINK but it hangs on me. Not sure why but I'll try again if I have time.

jj2007

Pushing three registers on the stack may have bad consequences in 64-bit land :eusa_naughty:

include \Masm32\MasmBasic\Res\JBasic.inc      ; ## console demo, builds with ML, AsmC, JWasm, HJWasm ##
Init            ; OPT_64 1      ; requires MasmBasic (and nothing else)
  PrintLine Chr$("This code was assembled with ", @AsmUsed$(1), " in ", jbit$, "-bit format")
  .data?
  buffer      dq 8 dup(?)
  .code
  push 88888888
  push 77777777
  push 66666666
  push 55555555
  push 44444444
  push 33333333
  push 22222222
  push 11111111
  mov rsi, rsp
  lea rdi, buffer
  mov ecx, 8
  rep movsq
  lea rsi, buffer
  .Repeat
      lodsq
      Print Str$("%i\n", rax)
  .Until rsi>=rdi
  Inkey "ok?"
EndOfCode


Output:
This code was assembled with HJWasm32 in 64-bit format
11111111
22222222
33333333
44444444
55555555
66666666
77777777
88888888
ok?

coder

Hi jj2007. Thanks for the reminder and nice to know you.

I think even or odd pushes will not affect the stack because I am designing it to work around TOS or specifically from the caller's TOS. As long as the user uses the stack correctly, this module should give persistent and accurate feedback. But I haven't tested it thoroughly though. 

Vortex

Hi coder,

Same code linked with GoLink :

\masm32\bin64\ml64.exe /c DisplayStack64.asm
\goasm\golink /console /entry mainCRTStartup DisplayStack64.obj kernel32.dll msvcrt.dll

coder

 Thanks a lot vortex. Exactly what I need.
Any idea why it fails on linking to kernel32.lib and msvcrt.lib using the same command?

Vortex

Hi coder,

GoLink is designed to import functions from DLLs not from import libraries :

QuoteInput files - dll/ocx/exe/drv files

Another type of input file is one containing exports, such as a DLL. Exports may be in DLL, OCX, DRV or other EXE files and you can provide the names of these in the command line or in a command file, or in your source code by using the directive #dynamiclinkfile if you are using GoAsm (see the GoAsm help file how to do this). Unlike other linkers there is no need to use LIB files. During the linking process GoLink looks at the list of files one by one for the required imports. When it has found all the required imports it will stop looking at the listed files. Because of this, GoLink will run more quickly if you list these files in order of popularity, by putting at the top of the list those which contains most of the required imports. Usually this order for the system DLLs is a good one:-

these contain most of the APIs you will be using:-

Kernel32.dll
User32.dll
Gdi32.dll

http://www.godevtool.com/GolinkFrame.htm



coder

#8
Thanks for the pointer Vortex. Now I know that even if .OBJ is a universal format, linkers may impose they own specific requirements.

I've updated the code by inserting an example on how to view the shadow space as per requirement of MS ABI. It is much clearer to me now. This is the output from the example code.

;; Demo: viewing the shadow space
;; ml64 stack64.asm /c
;; gcc -m64 stack64.obj -o stack64.exe

externdef printf:proc
option casemap:none

.code
main PROC
        mov     rcx,1          ;populate all four params
        mov     rdx,2
        mov     r8,3
        mov     r9,4

        sub     rsp,20h        ;allocate shadow space for Function A
        mov     [rsp   ],rcx   ;save volatiles (optional)
        mov     [rsp+ 8],rdx
        mov     [rsp+16],r8
        mov     [rsp+24],r9

        call    FunctionA

        mov     rcx,[rsp  ]    ;restore volatiles (optional)
        mov     rdx,[rsp+8]
        mov     r8,[rsp+16]
        mov     r9,[rsp+24]
        add     rsp,20h        ;delete shadow space of FunctionA
        ret
main ENDP

;;---------------------------------;;
;; Test function                   ;;
;;---------------------------------;;
align 16
FunctionA PROC
        mov     rcx,5
        call    dispStack  ;view shadow space
        ret
FunctionA ENDP


0000000000000004 <000000000062FE50    ;R9
0000000000000003 <000000000062FE48    ;R8
0000000000000002 <000000000062FE40    ;RDX
0000000000000001 <000000000062FE38    ;RCX
0000000000402D08 <000000000062FE30    ;caller's RIP


TWell

format string "%p %p" is shorter, if small letters are not a problem ;)

coder

That's even better TWell. Thanks. I've uploaded the shorter version according to your suggestion.

Increasing the stack count by 10 reveals that by default PROC/ENDP does not create a stack frame or prologue/epilogue for FunctionA. Wonder if it holds true if I used LOCAL inside FunctionA. Here's the output if I increased the magnitude to 10 instead of just 5

0000000000000000 <000000000062FE78
0000000000407A20 <000000000062FE70
0000000000000008 <000000000062FE68
0000000000000000 <000000000062FE60
00000000004013E8 <000000000062FE58    ;caller's /initial TOS
------- FunctionA shadow space -------
0000000000000004 <000000000062FE50    ;R9
0000000000000003 <000000000062FE48    ;R8
0000000000000002 <000000000062FE40    ;RDX
0000000000000001 <000000000062FE38    ;RCX
0000000000402D08 <000000000062FE30    ;caller's RIP / return address


Thanks for your help.


coder

#11
Had 1 hour spare time. I wrote the same code for 32-bit version. Link it with GCC.
Report bugs to me or modify it yourself. Have fun playing / experimenting with the stack.

EDIT: repair a bug in using (.if .endif. I am really that bad at using high-level statements ;D . Added example of negative view of the stack.



sinsi

Am I missing something?
Quote0000000000000001 <000000000062FE38    ;RCX
If that is the first param then it isn't aligned to 16

coder

Hi sinsi. Alignment is initiated by the user. This is a utility to view the stack, much like a debugger output. It makes no attempt to align the stack. What it does is to chase the Top of Stack at any point of choice. I hope this makes it clear.


sinsi